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 ^. ashould return. It has to pick something, so it tries to usememptyas a default instead of throwing an exception like_a Bdoes. - hammardata 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. - shachaflenshas several different lensy types. ALensis a reference to exactly one value "inside" another value. ATraversalis a reference to zero-or-more values. As such, using(^.)with aTraversalrequires aMonoidinstance 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,makeLensesgenerates aTraversalinstead of a crashingLens. Unfortunately this can lead to a confusing message aboutMonoid. - shachaf