Skip to content

Commit

Permalink
Add record lenses (#59)
Browse files Browse the repository at this point in the history
* Add record lenses

* Import fst, snd

* Use Lens synonym

* Update Record.purs
  • Loading branch information
paf31 authored Apr 13, 2017
1 parent e8d48d2 commit ba11011
Show file tree
Hide file tree
Showing 3 changed files with 72 additions and 6 deletions.
3 changes: 2 additions & 1 deletion bower.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,8 @@
"purescript-profunctor": "^3.0.0",
"purescript-sets": "^3.0.0",
"purescript-unsafe-coerce": "^3.0.0",
"purescript-transformers": "^3.0.0"
"purescript-transformers": "^3.0.0",
"purescript-symbols": "^3.0.0"
},
"devDependencies": {
"purescript-console": "^3.0.0"
Expand Down
64 changes: 64 additions & 0 deletions src/Data/Lens/Record.purs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
module Data.Lens.Record (prop) where

import Prelude
import Data.StrMap as S
import Data.Lens (Lens, lens)
import Data.Maybe (fromJust)
import Data.Symbol (class IsSymbol, SProxy, reflectSymbol)
import Partial.Unsafe (unsafePartial)
import Unsafe.Coerce (unsafeCoerce)

unsafeGet
:: forall r a
. String
-> Record r
-> a
unsafeGet s = unsafePartial fromJust <<< S.lookup s <<< unsafeCoerce

unsafeSet
:: forall r1 r2 a
. String
-> a
-> Record r1
-> Record r2
unsafeSet s a = unsafeCoerce <<< S.insert s a <<< unsafeCoerce

get
:: forall r r' l a
. IsSymbol l
=> RowCons l a r' r
=> SProxy l
-> Record r
-> a
get l = unsafeGet (reflectSymbol l)

set
:: forall r1 r2 r l a b
. IsSymbol l
=> RowCons l a r r1
=> RowCons l b r r2
=> SProxy l
-> b
-> Record r1
-> Record r2
set l = unsafeSet (reflectSymbol l)

-- | Construct a (type-changing) lens for a record property, by providing a
-- | proxy for the `Symbol` which corresponds to the property label.
-- |
-- | The lens is polymorphic in the rest of the row of property labels.
-- |
-- | For example:
-- |
-- | ```purescript
-- | prop (SProxy :: SProxy "foo")
-- | :: forall a b r. Lens { foo :: a | r } { foo :: b | r } a b
-- | ```
prop
:: forall l r1 r2 r a b
. IsSymbol l
=> RowCons l a r r1
=> RowCons l b r r2
=> SProxy l
-> Lens (Record r1) (Record r2) a b
prop l = lens (get l) (flip (set l))
11 changes: 6 additions & 5 deletions test/Main.purs
Original file line number Diff line number Diff line change
Expand Up @@ -6,25 +6,26 @@ import Control.Monad.Eff.Console (CONSOLE, logShow)
import Control.Monad.State (evalState, get)
import Data.Distributive (class Distributive)
import Data.Either (Either(..))
import Data.Lens (_1, _2, _Just, _Left, collectOf, lens, traversed, view)
import Data.Lens (view, traversed, _1, _2, _Just, _Left, lens, collectOf)
import Data.Lens.Fold ((^?))
import Data.Lens.Fold.Partial ((^?!), (^@?!))
import Data.Lens.Grate (cloneGrate, grate, zipWithOf)
import Data.Lens.Grate (Grate, cloneGrate, grate, zipWithOf)
import Data.Lens.Index (ix)
import Data.Lens.Lens (ilens, IndexedLens, cloneIndexedLens)
import Data.Lens.Record (prop)
import Data.Lens.Setter (iover)
import Data.Lens.Types (Grate)
import Data.Lens.Zoom (Traversal, Traversal', Lens, Lens', zoom)
import Data.Maybe (Maybe(..))
import Data.Symbol (SProxy(..))
import Data.Tuple (Tuple(..), fst, snd)
import Partial.Unsafe (unsafePartial)

-- Traversing an array nested within a record
foo :: forall a b r. Lens { foo :: a | r } { foo :: b | r } a b
foo = lens _.foo (_ { foo = _ })
foo = prop (SProxy :: SProxy "foo")

bar :: forall a b r. Lens { bar :: a | r } { bar :: b | r } a b
bar = lens _.bar (_ { bar = _ })
bar = prop (SProxy :: SProxy "bar")

type Foo a = { foo :: Maybe { bar :: Array a } }

Expand Down

0 comments on commit ba11011

Please sign in to comment.