Assumptions:
We can see that we can create a lens like this in Haskell:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
initialState :: Game
initialState = Game
{ _score = 0
, _units =
[ Unit
{ _health = 10
, _position = Point { _x = 3.5, _y = 7.0 }
}
]
}
health :: Lens' Unit Int
health = lens _health (\unit v -> unit { _health = v })
It's purpose is to get the health
value from the game
data structure.
We can access a nested structure using a key-sequence like this in Clojure:
(def initialState {:score 0
:units {:health 10
:position {:x 3.5
:y 7.0}}})
(def health [:units :health])
(defn initialState-getter [lens]
(get-in initialState lens))
(initialState-getter health)
> 10
(defn initialState-setter [lens value]
(assoc-in initialState lens value))
(initialState-setter health 22)
> {:score 0, :units {:health 22, :position {:y 7.0, :x 3.5}}}
Here we see a nested structure being updated by a key sequence.
My question is: What are the similarities and differences between a lens in Haskell and using a key-sequence in Clojure?
Lenses in Haskell are not restricted to keys. You could for example write a lens for the length of a string:
lengthLens = lens length setLength
setLength s l = take l s ++ take (l - length s) (repeat '\0')
Clojure key sequences are restricted to map/vector/etc keys. I personally don't think this is a loss since I've never had a need for lenses for non-key-like getters and setters.
As for types vs data, a lens composition in Haskell is data much like functions are data. This is similar to how vectors of keys are data in Clojure.