首页 > 解决方案 > 我在哪里定义任意实例?

问题描述

我不知道在哪里Arbitrary为我的数据类型定义实例。如果我把它放在包中,那么包不必要地必须QuickCheck作为依赖项。如果我把它放在测试中,那么其他包就不能使用这个实例。如果我把它放在一个单独的 test-utils 包中,那么测试必须放在一个单独的包中,所以它是一个孤儿实例, stack test --coverage不起作用。

还有哪些其他选择?

标签: haskelldependenciescode-coveragehaskell-stackquickcheck

解决方案


我通常会选择单独的包选项——但后来我不使用stack test --coverage. 感谢您向我介绍它!

(编辑:我可能会这样做,然后仅将测试标志选项用于运行stack test --coverage --flag thepackage:arbitrary,这样其他人就不必处理这些标志了。)

--coverage在问题跟踪器上提出问题也可能是值得的stack,因为在这种情况下覆盖检查工作会很好。

您要求其他选项 - 最好的选项可能是测试标志。

测试标志

可以在您的 cabal 文件中定义一个标志(默认为 false),如果选择了该标志,它将仅使用您的 QuickCheck 依赖项构建模块。

将所需的代码放在目录中arbitrary(例如)。然后将以下等效项添加到package.yaml(第一个片段)或the-library.cabal(第二个片段)文件的相关部分:

flags:
  arbitrary:
    description: Compile with arbitrary instances
    default: false
    manual: true

library:
  ⁝
  when:
  - condition: flag(arbitrary)
    dependencies:
    - QuickCheck
    source-dirs:
    - arbitrary
flag arbitrary
  description: Compile with arbitrary instances
  manual: True
  default: False

library
  ⁝
  if flag(arbitrary)
    hs-source-dirs:
      arbitrary
    build-depends:
      QuickCheck

然后,想要使用实例的包应在其stack.yaml(1st)或cabal.project(2nd)文件中添加以下内容:

flag:
  the-library:
    arbitrary: true
constraints: the-library +arbitrary

但是有一个小问题......目前该库无法仅依赖+arbitrary其测试套件中的版本,除非它还定义了这样的标志。这可能是一个值得付出的代价。

注意:我还没有测试过下游包装。

Ivan Milenovic 的博客作为初始资源很有用。

DerivingVia/通用实例

可能还有另一种可能性,现在 GHC 8.6 已经发布,带有DerivingVia. 例如,在Blöndal、Löh 和 Scott (2018)中有一个案例研究Arbitrary

您将创建新类型包装器,并Arbitrary为这些新类型实现。

它并没有完全避免这个问题,因为它是。但是您可能能够以Generic这样的方式实现这些新类型,即使用可派生的实例generic-arbitrary与您想要的匹配。


可能还有其他一些选择。特别是,QuickCheck的依赖关系实际上并没有那么重。还有其他测试库。另外,请注意,已经讨论了将Arbitrary-like 类型类分离为独立库的讨论。

我也会建议内部库,但这不允许其他包使用您的实例。


推荐阅读