I'm trying to build lenses for records which have the same field names. Along with that, I'm trying to "wrap/extend" these base records and want the same field names to work for the wrapped/extended records (which, I believe, classy lenses do). How do I get the following to work:
-- Data types for context of the code snippet below
data Download = Download {
userId :: UserId
,gid :: Gid
,logId :: LogId
,parentId :: Maybe DownloadId
,createdAt :: UTCTime
,updatedAt :: UTCTime
}
data File = File {
downloadId :: DownloadId
,fpath :: String
,len :: Int
,createdAt :: UTCTime
,updatedAt :: UTCTime
}
data Url = Url {
downloadId :: DownloadId
,fileId :: FileId
,url :: URL
,createdAt :: UTCTime
,updatedAt :: UTCTime
}
data DownloadObject = DownloadObject {
_key :: DownloadId
,_dbDownload :: Download
,_dbFiles :: [FileObjects]
}
data FileObject = FileObject {
_key :: FileId
,_dbFile :: File,
,_dbUrls :: [UrlObjects]
}
data UrlObject = UrlObject {
_key :: UrlId
,_dbUrl :: Url
}
fetchDownload :: DownloadId -> DownloadObject
Given these data types, how do I get the following lenses to work:
dload <- fetchDownload dloadId
dload ^. key -- of type DownloadId
dload ^. createdAt -- of type UTCTime
((dload ^. files) !! 1) ^. key -- of type FileId
((dload ^. files) !! 1) ^. createdAt -- of type UTCTime
András Kovács
Use makeFields
from Control.Lens.TH
:
{-# language
TemplateHaskell, MultiParamTypeClasses, FunctionalDependencies, FlexibleInstances #-}
import Control.Lens
data Bar a n = Bar {
_barAge :: a,
_barName :: n
} deriving Show
data Foo = Foo {
_fooAge :: Int,
_fooName :: String
} deriving Show
makeFields ''Bar
makeFields ''Foo
Now you have the following classes:
class HasName s a | s -> a where
name :: Lens' s a
class HasAge s a | s -> a where
age :: Lens' s a
and the appropriate instances for Foo
and Bar
. Example:
> Foo 10 "foo" ^. age
10
> Bar 10 "bar" ^. age
10
You can then implement the classes for wrapper objects. Example:
data FooWrapper = FooWrapper {
_fooWrapperKey :: Int,
_fooWrapperFoo :: Foo
} deriving Show
makeFields ''FooWrapper
instance HasName FooWrapper String where
name = foo . name
instance HasAge FooWrapper Int where
age = foo . age
来源:https://stackoverflow.com/questions/38914782/how-to-get-classy-lenses-with-overloaded-field-names