I have several data structures like
data Data1 = Data1
{ _data1Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data1
data Data2 = Data2
{ _data2Field :: Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data2
-- More similar data types
So I decided to write a simple type class to make it easier to compose
class HasField a where
field :: Lens' a Int
instance HasField Data1 where
field = data1Field
instance HasField Data2 where
field = data2Field
But then I ran into the problem that some of these structures have the corresponding field as optional
data Data3 = Data3
{ _data3Field :: Maybe Int
-- More fields
} deriving (Eq, Show)
makeLenses ''Data3
And now I can no longer use the type class. Since there are about the same number of data types that have that field optional as not, I decided that it'd be better to change the typeclass:
class HasField a where
field :: Lens' a (Maybe Int)
instance HasField Data3 where
field = data3Field
But since I'm not very experienced with the lens library, I'm stuck figuring out how to make this new lens work with the types for Data1
and Data2
. Ideally, I'd like to be able to view it and get a Maybe Int
value for any type, and when setting I'd like Just x
to set the field to x
for Data1
and Data2
and be a no-op for those two types when passed Nothing
.
Is this possible using existing combinators or am I going to have to write the lens myself? I'm fine doing so, but the majority of existing tutorials use TH and gloss over the details of writing one by hand.
I'm using GHC 7.6.3 and lens
3.10.
view l (set l x s) = x
, so if you set it toNothing
you must getNothing
when you view it. – shachafTraversal
, though (which is like a lens onto 0 or more values, rather than just one value). When you have aTraversal
you can usepreview
to view aMaybe
andset
to set. – shachafTraversal
for this? Also, would it be a problem if there are multiple fields like this for these records? – bheklilrTraversal
s? – bheklilr