Hi Emmanuel,
On Sun, Jul 14, 2013 at 10:47:16PM +0200, Emmanuel Surleau wrote:
> Hello there,
>Unfortunately you cannot do this using a Set. The reason is that
> The first (concrete) problem I ran into is how to update the members of a
> set with the result of an IO action. I have managed to do this with a pure
> function (prefixName) but I'm not sure of how to do this with
> promptName.
modifying the contents of a Set might result in a smaller Set and that
cannot possibly satisfy the lens laws. However, if we change the Set
of dogs to be a list, we can do this using the (%%~) operator:
> ... same as before ...
>
> data Dogs = Dogs { _dogs :: [Dog] }
> deriving Show
> makeLenses ''Dogs
>
> main :: IO ()> ... as before ...
> main = do
>> doggies' <- doggies & (dogs.traverse.name) %%~ prefixName
> -- change dog names by prompting the user
> print doggies'
>
> return ()
But astoundingly, if you look at the implementation of (%%~), it
is... (%%~) = id! So this code also works:
doggies' <- (dogs.traverse.name) prefixName doggies
That's right, the magic solution is to just treat the
(dogs.traverse.name) lens as a *function* and apply it to prefixName!
To understand why this works we have to look a bit at the
implementation. I am not surprised that you were baffled by it
because it looks quite magical if you don't understand where it comes
from.
Instead of trying to understand why this is the definition, let's just
> type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
see what happens if we take the right-hand side and set f = IO:
(a -> IO b) -> s -> IO t
In the above example, a = b = String, and s = t = Dogs, that is,
(dogs.traverse.name) has type
Lens Dogs Dogs String String
which expands to
(String -> IO String) -> Dogs -> IO Dogs
(actually this is a lie, it is really just a Traversal and not a Lens,
but it's the same idea). So if we apply it to 'prefixName :: String
-> IO String' we get a
function of type Dogs -> IO Dogs! Nifty!
Now, to answer your specific questions:
Yes, it is equivalent; the explicit forall is not strictly necessary.
> a) I'm not sure why the explicit forall is needed here (isn't this
> equivalent to just Functor f => ...)?
The forall is there to emphasize that the 'f' does not show up on the
left-hand side: something of type Lens s t a b is a function which
works for *any* specific Functor f that a user might choose. (E.g., we
specifically chose IO in the example above). So e.g. a lens cannot do
IO operations, because then it would only work for IO and not for
other Functors. So a lens may only interact with the f via the fmap
function. (Similarly a Traversal must work with all Applicatives, and
so on.)
You can think of lenses as generalizations of getters+setters, but
> b) My understanding is that a lens packs both getter and setters, but I
> don't know which is supposed to be which here...
that is NOT how they are implemented! Nothing in the type (a -> f b)
-> s -> f t corresponds directly to getters or setters.
For understanding more about what this type means and why it
corresponds to the idea of lenses, I highly recommend the video of
Edward's presentation to the NY Haskell user's group:
http://youtu.be/cefnmjtAolY?hd=1 .
You can find pretty much everything there is on lens here:
> c) Is there any kind of in-depth guide to Control.Lens somewhere? I have
> found some examples and tutorials but nothing that seemed to do more than
> scratch the surface.
http://lens.github.io/
-Brent
_______________________________________________
Beginners mailing list
Beginners@haskell.org
http://www.haskell.org/mailman/listinfo/beginners