Search code examples
haskellhaskell-lens

Monadic version of .~ (Haskell)


I'm looking for a version of .~ that takes a value wrapped in a Monad and returns a Monad. For example:

(0, 1) & _1 .~ 100 = (100,1)

Hypothetical .~~ would:

(0, 1) & _1 .~~ return 100 = return (100,1)

While it would not be hard to define, is it already defined somewhere in the Lens package?


Solution

  • I don't know about a single operator precisely like that, but with some "tiny" adjustments, this is essentially what the raw application of a lens does. The adjustments are:

    • You use a modifying function rather than just a setting value.
    • Your Monad needs to be a Functor, as nearly all are. (This will be mandatory from GHC 7.10, but isn't quite yet in 7.8.)

    So you can do:

    Prelude Control.Lens> (0,1) & _1 (const (Just 100))
    Just (100,1)
    Prelude Control.Lens> (0,1) & _1 (const [100])
    [(100,1)]
    Prelude Control.Lens> (0,1) & _1 (const [100,200])
    [(100,1),(200,1)]
    

    Even works with Traversals:

    Prelude Control.Lens> (0,1) & both (const [100,200])
    [(100,100),(100,200),(200,100),(200,200)]
    

    If you still want an operator too, the %%~ operator has been defined, but it's essentially a type-restricted synonym for id:

    Prelude Control.Lens> (0,1) & _1 %%~ const (return 100) :: Either () (Int,Int)
    Right (100,1)
    

    Finally, although you did say it was simple, your .~~ operator (which I think would logically be .%~ or the like if it were actually in lens) can be defined as just

    Prelude Control.Lens> let (.~~) = (. const)
    Prelude Control.Lens> (0,1) & _1 .~~ return 100 :: Either () (Int,Int)
    Right (100,1)