I'm currently experimenting with the JSaddle library in ghcjs.
I don't have much of any experience with lenses yet. Somewhere in this library they seem to define a getter lens which is actually a sort of monadic setter:
-- | Makes a setter for a particular property name.
--
-- > jss name = to (<#name)
--
-- >>> testJSaddle $ eval "'Hello World'.length = 12"
-- 12
-- >>> testJSaddle $ val "Hello World" ^. jss "length" 12
-- undefined
jss :: (ToJSString name, ToJSVal val)
=> name -- ^ Name of the property to find
-> val
-> forall o . MakeObject o => IndexPreservingGetter o (JSM ())
jss name val = to (\o -> o <# name $ val)
Using this in the following manner to set properties on a new javascript object works:
makeConfig :: JSM Object
makeConfig = do
object <- obj
object ^. jss "foo" 5
object ^. jss "bar" 7
return object
But I'd like to drop the cruft and have something like this:
makeConfig :: JSM Object
makeConfig = obj ^. jss "foo" 5
^. jss "bar" 7
I know you can do this in the lens library like this because the setters actually return the updated object:
obj & _1 .~ 45
& _2 .~ 49
Right now I made a small shim function that returns the input value every time:
(~.) :: MakeObject o => o -> IndexPreservingGetter o (JS.JSM ()) -> JS.JSM o
a ~. b = a ^. b >> return a
This allows me to use jss the way I'd like to:
makeConfig :: JSM Object
makeConfig = obj ~. jss "foo" 5
~. jss "bar" 7
But I can't help but feel that I'm trying to fix a solved problem. Is there a better way I don't know about?
[EDIT]
I did try something like this:
props :: MakeObject o => o -> [IndexPreservingGetter o (JS.JSM ())] -> JS.JSM o
props object p = mapM_ (object ^.) p >> return object
But then GHCJS complains about impredicative polymorphism...