Haskell 如何获得具有过载字段名称的经典镜头?

Haskell 如何获得具有过载字段名称的经典镜头?,haskell,haskell-lens,lenses,Haskell,Haskell Lens,Lenses,我正在尝试为具有相同字段名的记录构建镜头。除此之外,我正在尝试“包装/扩展”这些基本记录,并希望相同的字段名适用于包装/扩展的记录(我相信,经典镜头可以做到这一点)。如何使以下各项发挥作用: -- Data types for context of the code snippet below data Download = Download { userId :: UserId ,gid :: Gid ,logId :: LogId ,parentId :: Maybe Do

我正在尝试为具有相同字段名的记录构建镜头。除此之外,我正在尝试“包装/扩展”这些基本记录,并希望相同的字段名适用于包装/扩展的记录(我相信,经典镜头可以做到这一点)。如何使以下各项发挥作用:

-- 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
鉴于这些数据类型,我如何使以下镜头工作:

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

dload使用
makeFields
from:

现在您有了以下类:

class HasName s a | s -> a where
  name :: Lens' s a

class HasAge s a | s -> a where
  age :: Lens' s a
以及
Foo
Bar
的相应实例。例如:

> Foo 10 "foo" ^. age
10
> Bar 10 "bar" ^. age
10
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
然后可以实现包装器对象的类。例如:

> Foo 10 "foo" ^. age
10
> Bar 10 "bar" ^. age
10
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

谢谢你的回复。我认为你错过了问题的关键部分。我想让镜头处理包装/扩展的记录,即
下载对象
文件对象
,和
UrlObject
,而不是
下载
文件
,以及
Url
,有没有其他方法可以在不必自己编写所有镜头相关的模板的情况下编写这些记录(HasName
HasAge
等实例)?一个糟糕的答案:你可以使用模板Haskell来自动化大部分内容。它的API和文档很复杂,但它是可行的。据我所知,lens库没有提供这样做的方法。啊……我多么怀念Ruby元编程和Lisp宏!