Translating "Putting Lenses to Work" into PureScript (Part 1)


August 2019 Update: There are now much better resources for learning PureScript lenses! Take a look at Thomas Honeyman's article Practical Profunctor Lenses & Optics In PureScript. What follows is my REPL session using PureScript v0.11.5. Since we're now on v0.13.2, some of the syntax may be out of date.


In June of 2017, John Wiegley presented Putting Lenses to Work and did a great job explaining lenses in Haskell. The use of lenses in PureScript is the same, albeit the syntax is slightly different. This post is the PureScript REPL session where I followed along (up till 23:51) and uses purescript-profunctor-lens.

A few introductory notes. The & operator is used in the video. This is for reverse application, and the PureScript equivelent is the # operator.

The following operators/functions can be found in these modules...

Function Module
(^?) (preview) Data.Lens.Fold
(ix) Data.Lens.Index
at Data.Lens.At
non Data.Lens.ISO
use Data.Lens.Getter
to Data.Lens.Getter
(^..) (toListOfOn) Data.Lens.Getter
(^?!) (unsafeView) Data.Lens.Getter

> newtype Recipe = Recipe { title :: String }
> instance showRecipe :: Show Recipe where show (Recipe {title}) = "Recipe: " <> title
> recipe = Recipe { title : "Brownies" }
> import Data.Lens
> _title = lens (\(Recipe {title}) -> title) (\(Recipe r) value -> Recipe (r {title = value}))

-- Getting Values - 2:42
> view _title recipe
Brownies

-- Setting Values - 3:31

> over _title (const "New Recipe") recipe
Recipe: New Recipe

> recipe # _title %~ (const "New Recipe")
Recipe: New Recipe

> (_title %~ (const "New Recipe")) recipe
Recipe: New Recipe

> _title %~ (const "New Recipe") $ recipe
Recipe: New Recipe


-- Prisms - 10:17

> import Data.Maybe
> view _Just (Nothing :: Maybe String)
""

> view _Just (Just "abc")
"abc"

> b = Just "hi."
> view _Just b
"hi."
> over _Just (flip append "goodbye") b
"hi.goodbye"

> over _Just (flip append "goodbye") b
Nothing

-- 16:05 Traversable

> import Data.Lens.Index
> [1,2,3] # ix 2 .~ 20
[1,2,20]

> [1,2,3] # ix 6 .~ 20
[1,2,3]

> b ^.. _Nothing
Nil

b ^.. _Just
> ("hi." : Nil)

--- 17:17

> import Data.Traversable
> import Data.Monoid.Additive
> [1,2,3,4] ^. (to (foldMap Additive))
(Additive 10)

---

> import Data.Tuple
> even a = mod a 2 == 0
> allOf _2 even (Tuple 1 1)
false

---

> allOf (traversed) even [2,2,1]
false

> allOf (traversed) even [2,2,2]
true

> allOf (traversed <<< _2) even [Tuple 2 1]
false

> allOf (traversed <<< _2) even [Tuple 2 2]
true

--- 21:08

> import Data.StrMap as StrMap
> import Data.Lens.At
> strmap = StrMap.fromFoldable [Tuple "user" "john", Tuple "id" "1"]
> strmap ^. (at "user")
Just "john"

> import Data.Map as Map
> mymap = Map.fromFoldable [Tuple 1 "john", Tuple 2 "terry"]
> mymap ^. (at 1)
Just "john"

> mymap ^. (at 5)
Nothing

--- 22:33

> mymap ^. at 5 <<< non "Not Found"
Just "Not Found"

-- 22:53

> mymap ^? ix 1
(Just "john")

> mymap ^? ix 7
Nothing

---

> import Partial.Unsafe
> import Data.Lens.Fold.Partial
> unsafePartial (mymap ^?! ix 1)
"john"

--- 23:24

> mymap # ix 1 .~ "5"
(fromFoldable [(Tuple 1 "5"),(Tuple 2 "terry")])

> mymap # ix 10 .~ "5"
(fromFoldable [(Tuple 1 "john"),(Tuple 2 "terry")])

--- 23:51

There doesn't appear to be a purescript-profunctor-lens equivelent of `failing`