makeFields, polymorphic lens
makeFields, polymorphic lens
Module A:
data Xxx a = Xxx {
_xxxAaa :: Int,
_xxxBbb :: a
}
makeFields ''Xxx
Module B:
t :: IO Bool
t = do
let n = "aaa" :: String
let xs = [Xxx 0 0, Xxx 1 1] :: [Xxx Int]
ys = [set bbb n $ x | x <- xs]
pure False
Error is:
• Couldn't match type ‘Int’ with ‘[Char]’
arising from a functional dependency between:
constraint ‘HasBbb (Xxx Int) String’ arising from a use of ‘bbb’
instance ‘HasBbb (Xxx a) a’
at .........
Pay attention, makeFields generates not a polymorphic lenses, ie, it cannot change the type like with usual record constructors:
let xs = [Xxx 0 0, Xxx 1 1]::[Xxx Int]
ys = [x {_xxxBbb="aaaa"} | x <- xs]
ie, from Xxx Int to Xxx String. But makeLens generates polymorphic lenses. It can be checked with :i in GHCI:
ghci> :i HasBbb
class HasBbb s a | s -> a where
bbb :: Lens' s a
{-# MINIMAL bbb #-}
-- Defined at A.hs:14:1
instance HasBbb (Xxx a) a -- Defined at A.hs:14:1
we see that makeFields generates class HasBbb. And it looks like Lens' s a is a short variant of Lens ... where type-from and type-to are the same (ie, it does not allow to change the type with a setting operation). But a lens via makeLens:
data Xxx a = Xxx {
_xxxAaa :: Int,
_xxxBbb :: a
}
makeFields ''Xxx
makeLenses ''Xxx
Let's check:
ghci> :i xxxBbb xxxBbb :: Lens (Xxx a1) (Xxx a2) a1 a2 -- Defined at A.hs:15:1 ghci> :t set xxxBbb "aaa" (Xxx 0 0) set xxxBbb "aaa" (Xxx 0 0) :: Xxx [Char]
We see that xxxBbb is polymorphic and it changes the type Xxx a1 -> Xxx a2 when we set the field of type a1 into a2. Something like this :)
And set xxxBbb "aaa" (Xxx 0 0) works now (and with .~ even).