You’ve completed the Data61 FP Course. You’ve gone on and finished every single exercise in the QFPL Applied FP Course. You know what you’re doing, so you join a Haskell project, and are presented with:
update things thing =
let thatThing = Map.lookup (thing ^. properties . identifier) things
thingName = thatThing <&> view (metadata . name)
thingResponsibilities = thatThing <&> view responsibilities
in thing & name .~ thingName
& responsibilities <>~ thingResponsibilities
& age %~ (* 2)
This looks nothing like the language you’ve been using! How can it be this different? How are you supposed to contribute to this project?!
Well, it would help if you could read lens
syntax. This post is what I wish I had the first time I encountered code like this.
&
and <&>
x & f
is equivalent to
f $ x
which is just
f x
The two syntaxes can be interlaved. Pretend you’re in an object-oriented language and read x & p & q
as x.p.q
. So:
f $ g $ x & p & q $ h
is equivalent to
f (g ((q (p x)) h))
Similarly,
x <&> f
is equivalent to
f <$> x
Automatically generated lenses
This syntax:
data MyRecord {
_property :: String,
_otherProperty :: Int
}
makeLenses ''MyRecord
generates these additional definitions:
property :: Lens' MyRecord String
otherProperty :: Lens' MyRecord Int
Don’t worry about what Lens'
means, just know that you won’t be able to use grep
to locate the definitions of thatProperty
and otherProperty
. Try looking for the property prefixed with _
.
Reading properties out of things
thisThing ^. property . subProperty . subSubProperty
is equivalent to
view (property . subProperty . subSubProperty) thisThing
and
_subSubProperty . _subProperty . _property $ thisThing
Changing properties of things
thisThing & property . subProperty . subSubProperty .~ newValue
& property . otherProperty %~ updateValue
& otherStuff <>~ stuffs
is equivalent to
over otherStuff (<> stuffs)
$ over (property . otherProperty) updateValue
$ set (property . subProperty . subSubProperty) newValue
$ thisThing
and
thisThing {
_property = _property thisThing {
_subProperty = _subProperty (_property thisThing) {
_subSubProperty = newValue
},
_otherProperty = updateValue (_otherProperty (_property thisThing)),
_otherStuff = _otherStuff (_property thisThing) <> stuffs
}
}
This is… not very readable. No wonder lenses were invented!