如何解决无法使用存在类型镜片的问题?

Ire*_*app 6 haskell existential-type lenses haskell-lens

我第一次使用Edward Kmett的镜头库,发现它相当不错,但我遇到了麻烦...

[1]中的问题解释了存在量词会破坏makeLenses.我真的很想以某种方式使用带镜片的存在主义.

作为背景,我有课:

class (TextShow file, Eq file, Ord file, Typeable file) => File file where
  fromAnyFile :: AnyFile -> Maybe file
  fileType :: Simple Lens file FileType
  path :: Simple Lens file Text.Text
  provenance :: Simple Lens file Provenance
Run Code Online (Sandbox Code Playgroud)

对于实际问题,我想要的类型:

data AnyFile = forall file . File file => AnyFile { _anyFileAnyFile :: File }
Run Code Online (Sandbox Code Playgroud)

我希望能够写下以下内容:

instance File AnyFile where
  fromAnyFile (AnyFile file) = cast file
  fileType (AnyFile file) = fileType . anyFile
  path (AnyFile file) = path . anyFile
  provenance (AnyFile file) = provenance . anyFile
Run Code Online (Sandbox Code Playgroud)

由于[1]中解释的原因,这不起作用.如果我通过编译要求GHC调试信息-ddump-splices,我得到:

Haskell/Main.hs:1:1: Splicing declarations
    makeLenses ''AnyFile ======> Haskell/Main.hs:59:1-20
Run Code Online (Sandbox Code Playgroud)

拼接本身是空白的,这表明我没有声明它.这部分我现在期待并理解我已阅读​​[1].

我想知道的是我如何做到这一点 - 我可以做些什么来解决这个问题?我该怎么办才能避免在上游游泳?我希望能够通过组合镜头的路径访问我的结构的任何部分,但是因为我有其他类型的字段,例如Set AnyFile,我不能这样做,除非我可以访问AnyFile镜头的内容.

[1] 存在量词静默地破坏模板Haskell(makeLenses).为什么?

Tik*_*vis 7

在最糟糕的情况下,您可以自己实施镜头而不依赖于模板Haskell.

例如,给定类型的getter和setter函数,您可以使用以下lens函数创建镜头:

 lens :: (s -> a) -> (s -> b -> t) -> Lens s t a b
Run Code Online (Sandbox Code Playgroud)

我相信这可能不是最有效的选择,但它肯定是最简单的.

我不知道如何为你的情况(或一般的存在类型)做这个,但这里是一个使用记录的简单例子:

data Foo = Foo { _field :: Int }
foo = lens _field (\ foo new -> foo { _field = new })
Run Code Online (Sandbox Code Playgroud)

希望这足以说明这个想法适用于您的代码.

  • @IreneKnapp:别担心.我很高兴你让它运转起来. (2认同)