I was coding with with the lens package. Everything was going fine until I tried to access a certain field on an algebraic type:
import Control.Lens
data Type = A { _a :: Char } | B
makeLenses ''Type
test1 = _a (A 'a')
test2 = (A 'a') ^. a
No instance for (Data.Monoid.Monoid Char)
arising from a use of `a'
Possible fix:
add an instance declaration for (Data.Monoid.Monoid Char)
In the second argument of `(^.)', namely `a'
In the expression: (A 'a') ^. a
In an equation for `test2': test2 = (A 'a') ^. a
I could just go with _a, but the datatype in my real program is much deeper and I kind of intended on using lens to lower the amount of work I have to do. I have been looking over the lens library but there's so much there, and I'm not sure if he's dealt with this scenario or it is just something the lens library doesn't support.
As a side note, if I actually use a monoid like String for the datatype instead of Char, it then compiles and gives the right answer, I have no idea why.
Edit: After reading hammar's comment, I tried this and this works:
test2 = (A 'a') ^? a
test3 = B ^? a
But it is kind of weird to get a maybe out of that for something that has to exist.
B ^. a
should return. It has to pick something, so it tries to usemempty
as a default instead of throwing an exception like_a B
does. – Humphriesdata Foo = One { x :: Int } | Two { x :: Int }
. But otherwise, yes, it's a partial function, and it's a shame that it's so easy to introduce it without warnings. – Skileslens
has several different lensy types. ALens
is a reference to exactly one value "inside" another value. ATraversal
is a reference to zero-or-more values. As such, using(^.)
with aTraversal
requires aMonoid
instance to supply a value (in case there are none) or to combine values (in case there's more than one).(^?)
is a convenience function that gives you the first value, if there are any. To avoid partiality,makeLenses
generates aTraversal
instead of a crashingLens
. Unfortunately this can lead to a confusing message aboutMonoid
. – SkilesPrism
is supposed to do? I'm surprised nobody has mentioned that. – CleromancyA
Prism
, but I thought that was a bit out of scope here. E.g. if you wrotedata Foo = A { _a :: Int, _b :: Char } | B
, then you wouldn't have prisms, just (affine) traversals. (You could still have aPrism' Foo (Int,Char)
but that's a bit far from the original question. Also, then I'd have to explain prisms!) – Skiles