view 6-Clojure/bearings.clj @ 89:7e4afb129bef

Add initial Day 2 notes with functions, partially applied, and currying
author IBBoard <dev@ibboard.co.uk>
date Sat, 15 Jun 2019 21:07:27 +0100
parents eccc649d49a2
children
line wrap: on
line source

; Based on Compass
(def directions [:north :east :south :west])

; Define a "fixed movement" protocol - "m" is effectively "this"
(defprotocol FixedMovement
    (direction [m]) ; Find your current direction
    (left [m]) ; turn left one position
    (right [m])) ; turn right one position

; Define an implementation with a single field (not a parameter - although it's defined the same)
(defrecord CompassBearings [bearing]
    ; Specify which protocol we're implementing
    FixedMovement
    ; And define the methods
    (direction [_] (directions bearing)) ; Look-up our index in the list
    ; Clojure uses immutable values, so these functions create new CompassBearing objects
    (left [_] (CompassBearings. (mod (- bearing 1) (count directions)))) ; Create a new instance (ClassName.) with a value from rotating one slot left
    (right [_] (CompassBearings. (mod (+ bearing 1) (count directions))))
    ; And we can specify more
    Object
    (toString [this] (str "[" (direction this) "]")) ; Presumably we could also call (directions bearing) directly.
    ; We have to pass something to (direction) because we're doing functions and so can't do "obj.function()" to keep the reference to what we're getting directions of.
    )

; Define a thing that has bearings - e.g. an actor in a scene
; It'd be nice if we could do an automated default so that we're not passing in magic numbers
(def actor (CompassBearings. 0))
(println actor) ; Prints default internal format
(println (:bearing actor)) ; Access a field using the keyword as a function. Because keywords with meaning happen EVERYWHERE in Clojure!
(println (str actor)) ; Uses our toString method
(println (str (left actor)))
(println (str (right (right actor))))