Search code examples
haskellhaskell-lens

How do you fmap a Getter?


As discussed on reddit, you can't just lift a Lens' a b to Lens' (Maybe a) (Maybe b). But for the special case Getter a b, this is obviously possible, since it's isomorphic to a->b. But unlike with Iso, there appears to be no standard function to perform this lift.

What's the preferred way to do that? In cases like

    someFunction $ myMap^.at(i).ꜰᴍᴀᴘGᴇᴛ(mySubGetter)

I could of course do

    someFunction $ myMap^.at(i) & fmap (^.mySubGetter)

but that doesn't work as well in other applications, as when operating on a state monad.

    foo <- use $ myMapInState.at(i).ꜰᴍᴀᴘGᴇᴛ(mySubGetter)

Solution

  • I believe you can accomplish what you want with a prism.

    If your values have these types:

    myMap :: Map String (Int, String)
    myMap = mempty
    
    mySubGetter :: Lens' (Int, String) String
    mySubGetter = _2
    

    then you can do:

    myVal :: Maybe String
    myVal = myMap ^? at "myKey" . _Just . mySubGetter
    

    If you just want to apply a function to a getter you can use the to function from Control.Lens.Getter, you have to manually deal with the sublens though:

    someFunction $ myMap ^. at(i) . to (fmap (^. mySubGetter))