gpt4 book ai didi

haskell - 使用模板 haskell 定义实例时避免孤立实例

转载 作者:行者123 更新时间:2023-12-04 10:25:35 26 4
gpt4 key购买 nike

我想定义一个导出类 C 的 Haskell 模块和 C 的实例对于各种类型。因为我想定义很多可以按照给定方案自动定义的实例,所以我定义了一个辅助 TH 函数来定义实例,有点像这样:

module Foo (C) where

class C a

defineCInstance :: TypeQ -> DecsQ
defineCInstance t =
[d|
instance C $t
|]

defineCInstance [t| () |]
defineCInstance [t| Char |]
defineCInstance [t| Int |]

但是上面的例子没有编译通过,因为阶段限制,不允许使用 defineCInstance在定义它的同一模块中的拼接中。这可以通过移动 defineCInstance 来修复进入一个新模块(我们称之为 Foo.Internal )并将其导入 Foo .但是,当我只是移动 defineCInstance进入另一个模块它不会有 C在范围内,我目前看到了两种解决此问题的方法。

解决方案1,移动 C进入 Foo.Internal以及

如果我同时移动 defineCInstanceC进入 Foo.Internal defineCInstance可以轻松引用 C我可以拼接 defineCInstanceFoo没有问题。但是, Foo 中定义的实例不会在与 C 相同的模块中定义不再,因此成为孤儿实例。我想避免这种情况,因为那样我将不得不对孤儿的警告静音,这对于整个文件来说是 AFAIK 唯一可能的,并且可能会对同一文件中的其他意外孤儿实例的警告静音。我还注意到 haddock 然后将所有实例列为文档中的孤立实例,我也想避免这种情况。

解决方案2,不要让 defineCInstance引用 C直接地。

而不是引用 instance C里面 defineCInstance我可以使用 instance $(conT $ mkName "C") 之类的东西反而。然而,这隐藏了 C 之间的依赖关系。和 defineCInstance来自编译器,这使得错误更有可能发生。例如,如果我重命名 C ,但忘记在 defineCInstance 中更改名称编译器仍然会愉快地编译 defineCInstance .更糟糕的是,它依赖于正确的 CdefineCInstance 的拼接位点范围内.如果用户有错误 C在范围内,生成的代码将完全没有意义。

有什么方法可以定义 C , defineCInstance以及 C 的实例在某种程度上,仍然允许引用 C直接来自 defineCInstance 避免定义孤儿实例?

最佳答案

  • 定义一个内部 defineCInstance_这需要 NameC作为参数;
  • 在外部 Foo包含类的模块,使用 defineCInstance_ ''Foo.C对于标准实例;
  • 导出 defineCInstance = defineCInstance_ ''Foo.C ,防止用户使用错误的名称。

  • 在第 2 步中,您可以将所有相关类型放在一个列表中并一次遍历它,因此您只需引用 ''Foo.C两次命名:一次在拼接中,一次在导出的 defineCInstance 中.

    关于haskell - 使用模板 haskell 定义实例时避免孤立实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/60641765/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com