Haskell 中的扩展结构

Extending structures in Haskell

我想实现一些具有一组通用参数的算法(实际上这是一个很大的数字,这就是为什么我没有将它们单独传递到函数中的原因):

data Parameters = Parameters {
   _p1 :: A,
   ...
}

但他们每个人都有 - 除了这个通用集 - 一组只有他们知道如何使用的参数:

data AlgorithmAParameters = AlgorithmAParameters {
    _commonParameters :: Parameters,
    _myp1 :: B
}

这里的问题是如何编写地道的代码。我目前正在使用镜头,所以我可以定义

p1 :: Lens' AlgorithmAParameters A
p1 = commonParameters . Common.p1

这让我可以像只使用 Parameters 一样访问所有内容。问题是我必须为每个保留自己的参数集的算法执行此操作,并且我必须小心地分别导入这些参数。

我可以更进一步,使用类型 classes

class Parameters p where
    p1 :: Lens' p A
    ...

然后分别实现

class AlgorithmAParameters p where
    p1 :: Lens' p A
    myp1 :: Lens' p B

AlgorithmAParameters p => AlgorithmParameters p 实例一起。但是,这具有相同类型的问题(重复代码)并最终导致代码与第一个选项一样具有误导性(加上类型 class 中的整个 Lens' 不是很有用)。

有没有更简单的方法来解决这个问题?

您要查找的是 Control.Lens.TH 中的 makeClassy。阅读有关其对字段名称的假设的文档。 (如果您无法更改您的字段名称以匹配查看朋友 makeClassyFormakeClassy_

这里的想法是,模板创建一个 class 的事物,其中包含您的 commonParameters 并将您的数据结构添加为该 class 的实例。当许多数据结构具有相同的字段时,它们都将属于相同的 class。然后,您可以在镜头配件中使用 class。

作为编程笔记,我倾向于使用只是 commonParameters 和一个合理的名称来制作一个通用结构,这样我就可以参考class由 TH 使用 HasFoo 约定创建。

classy lenses/optics 技巧在这里很有用。

data CommonParameters = CommonParameters
  { _p1 :: A
  }
makeClassy ''CommonParameters

makeClassy 模板 Haskell 指令将导致以下 class 和实例:

class HasCommonParameters a where
  commonParameters :: Lens' a CommonParameters
  p1 :: Lens' a A
  p1 = ... -- default implementation

instance HasCommonParameters CommonParameters where
  commonParameters = id

然后 AlgorithmParameters

data AlgorithmParameters = AlgorithmParameters
  { _algCommonParameters :: CommonParameters
  , _myp1 :: B
  }
makeClassy ''AlgorithmParameters

再次 makeClassy 做它的事情:

class HasAlgorithmParameters a where
  algorithmParameters :: Lens' a AlgorithmParameters
  algCommonParameters :: Lens' a CommonParameters
  algCommonParameters = ... -- default implementation
  myp1 :: Lens' a B
  myp1 = ... -- default implementation

instance HasAlgorithmParameters AlgorithmParameters where
  algorithmParameters = id

现在,您可以将 CommonParameters 光学元件与 AlgorithmParameters类型,定义如下实例:

instance HasCommonParameters AlgorithmParameters where
  commonParameters = algCommonParameters