aula icon indicating copy to clipboard operation
aula copied to clipboard

Add initial lens faq.

Open fisx opened this issue 8 years ago • 10 comments

fisx avatar Mar 29 '16 15:03 fisx

not sure about the title of the older question; if somebody has a better idea...

@np: answer and context to first question missing. thanks! (-:

fisx avatar Mar 29 '16 15:03 fisx

Here are a few hints at using lenses based on examples.

modifyDb_ :: AulaSetter a -> (a -> a) -> AUpdate ()
modifyDb_ l f = AUpdate . ExceptT . fmap Right $ modify (l %~ f)

First there is no need to wrap the AUpdate stack ourself, this works: modifyDb_ l f = modify (l %~ f).

Then instead of modify (l %~ f) one can use l %= f the mnemonic is that ~ is for functional update and = for MonadState updates.

modifyDb :: AulaLens a -> (a -> a) -> AUpdate a
modifyDb l f = AUpdate . ExceptT . fmap Right $ state (\s -> (f $ s ^. l, l %~ f $ s))

The first remark still applies, secondly this kind of update which also returns the computed result is called a «pass-through» update in lens. The symbol for that in lens is <, so:

  • s & l <+~ 1 returns both the new targeted value and the full updated value: (s ^. l + 1, s & l +~ 1).
  • l <+= 1 increments the state by 1 at location l and returns new targeted value: do { x <- view l; l += 1; pure (x + 1) }.

Some more hints:

  • l .~ Just x becomes l ?~ x.
  • l .= Just x becomes l ?= x.
  • l1 %~ (l2 .~ x) becomes l1 . l2 .~ x.
  • l1 %~ (l2 %~ f) becomes l1 . l2 %~ f.
  • l %~ const x becomes l .~ x.
  • s & l .~ x tends to be more readable than l .~ x $ s
  • id .~ x becomes const x
  • id .= x becomes put x
  • id %~ f becomes f
  • id %= f becomes modify f
  • (l .= x) >> pure x becomes l <.= x

np avatar Apr 06 '16 14:04 np

also we should make a list of good resources:

  • spj's skills matter talk
  • kmett's boston meetup marathon
  • ...?
  • reading material?

fisx avatar Apr 06 '16 21:04 fisx

questions from #342:

[...]
        <$> ("email"         .: (email & prelens emailAddress %%~ DF.optionalText))
[...]
        "email"         -> pure [TextInput $ email ^. _Just . re emailAddress]
[...]
        <*> ("desc"  .: ((topic ^. topicDesc) & _Markdown %%~ (DF.text . Just)))
[...]

fisx avatar Apr 08 '16 20:04 fisx

("email" .: (email & prelens emailAddress %%~ DF.optionalText))

The prelens function is gone now and there is a comment about it.

"email" -> pure [TextInput $ email ^. _Just . re emailAddress]

The doc for emailAddress addresses that.

("desc"  .: ((topic ^. topicDesc) & _Markdown %%~ (DF.text . Just)))

Let's abstract (topic ^. topicDesc) as s and (DF.text . Just) as f. We get: s & _Markdown %%~ f. The operator %%~ is like %~ but works with effectful functions (a -> f b). So this is equivalent to unwrapping the Markdown constructor calling f and wrapping the constructor back again.

np avatar Apr 13 '16 08:04 np

[copied from https://github.com/liqd/aula/pull/360#discussion_r59679339]

instead of

maybe "" id pw

you can write:

pw ^. _Just

This works because when ^. is applied to a Prism it goes down to a Fold and get this type: (^.) :: Monoid a => s -> Fold s a -> a. In our case (^.) :: Maybe ST -> Fold (Maybe ST) ST -> ST which means that the monoid instance for ST is doing the work of defaulting to the empty string.

fisx avatar Apr 14 '16 09:04 fisx

[irc]

14:57 < npou> fisx_: anyOf is like any but instead of working directly on the
                     containers it applies a lens first

fisx avatar May 03 '16 12:05 fisx

[irc]

15:13 < fisx_> npou: is there a type synonym for this?:
15:13 < fisx_> (Monoid (f User), Functor f, Applicative f, Contravariant f) => 
               (ST -> f ST) -> User -> f User
15:52 < npou> fisx_: the good one is called Getting, the trick was to look at 
              the type sig of anyOf, it takes a `Getting Any s a`.
15:54 < npou> so searchee can be either: `Getting Any User ST` or more generally 
              `Monoid r => Getting r User ST`.

fisx avatar May 03 '16 13:05 fisx

[irc]

15:57 < npou> While Fold is defined as `type Fold s a = forall f. (Contravariant f, 
              Applicative f) => (a -> f a) -> s -> f s`, the docs gives a simpler 
              version: `type Fold s a = forall m. Monoid m => Getting m s a`
15:59 < npou> correspondingly Getter is equivalent to `type Getter s a = forall r. 
              Getting r s a`, which means that we know nothing about `r` hence we can't 
              use it as a monoid
16:00 < npou> So Getting is to keep in mind when using lenses with monoids
16:01 < npou> Also often `r` is equal to `a` as in the type of `view :: MonadReader s m 
              => Getting a s a -> m a`
16:02 < npou> or `(^.) :: s -> Getting a s a -> a`
16:02  * npou tries to get a better grasp at Getting by explaining it...
16:04 < npou> the catch is that searchee ought to be a `Fold User ST` following the 
              "definition" of Fold above.

fisx avatar May 03 '16 14:05 fisx

https://en.wikibooks.org/wiki/Haskell/Lenses_and_functional_references#The_scenic_route_to_lenses

fisx avatar May 07 '16 14:05 fisx