Reputation: 1469
I'm trying to compose a Lens and a Prism in Haskell, and not getting the answer I expected. Here is my test code:
{-# LANGUAGE OverloadedStrings #-}
import Data.Function ( ($), (&) )
import Control.Lens.Getter ( (^.) )
import Control.Lens.Lens ( Lens', lens )
import Control.Lens.Prism ( Prism', prism )
import Control.Lens.Setter ( (.~) )
import Control.Lens.Review ( AReview, re )
import Control.Lens.TH ( makeClassy )
(##) :: AReview t s -> s -> t
x ## y = y ^. re x
data Test = T1 Int | T2 String
deriving Show
_T1 :: Prism' Test Int
_T1 = prism T1 (\x -> case x of T1 i -> Right i; _ -> Left x)
_T2 :: Prism' Test String
_T2 = prism T2 (\x -> case x of T2 t -> Right t; _ -> Left x)
data Combi = Combi { _t :: Test }
deriving Show
defCombi :: Combi
defCombi = Combi (T1 7)
t :: Lens' Combi Test
t = lens (\(Combi x) -> x) (\( Combi _ ) t' -> Combi t')
test = (defCombi & t .~ (_T2 ## "foo"), defCombi & (t . _T2) .~ "bar")
Now my surprise is that when I run this, the second of the pair shows Combi {_t = T1 7}
; that is, the "assignment" via t . _T2 has no effect.
Looking at the types, the apparently relevant detail is that composing t with _T2 promotes the "Functor" requirement to an "Applicative" requirement.
*Main
λ> :t t
t :: Functor f => (Test -> f Test) -> Combi -> f Combi
*Main
λ> :t t . _T2
t . _T2
:: Applicative f => (String -> f String) -> Combi -> f Combi
But quite frankly, I can't get my head around what this means, and particularly why this means that the composition doesn't "work" (or, more likely, that it does work, but I'm misunderstanding what it means in this context).
Any enlightenment gratefully received.
Upvotes: 1
Views: 942
Reputation: 17786
When you use a Prism
, or indeed any Traversal
as a setter, it only works if the argument is already on the correct variant.
Prelude> :module + Control.Lens
Prelude Control.Lens> (Left 4) & (_Left .~ "foo")
Left "foo"
Prelude Control.Lens> (Left 4) & (_Right .~ "foo")
Left 4
Thus when you apply _T2 .~ "bar"
to T1 7
you get T1 7
instead of T2 "bar"
Upvotes: 1