
Hi Emmanuel, On Sun, Jul 14, 2013 at 10:47:16PM +0200, Emmanuel Surleau wrote:
Hello there,
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.
Unfortunately you cannot do this using a Set. The reason is that 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 () main = do ... as before ...
-- change dog names by prompting the user doggies' <- doggies & (dogs.traverse.name) %%~ prefixName 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.
type Lens s t a b = forall f. Functor f => (a -> f b) -> s -> f t
Instead of trying to understand why this is the definition, let's just 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:
a) I'm not sure why the explicit forall is needed here (isn't this equivalent to just Functor f => ...)?
Yes, it is equivalent; the explicit forall is not strictly necessary. 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.)
b) My understanding is that a lens packs both getter and setters, but I don't know which is supposed to be which here...
You can think of lenses as generalizations of getters+setters, but 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 .
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.
You can find pretty much everything there is on lens here: http://lens.github.io/ -Brent