扩展Haskell中的结构

时间:2017-09-05 21:05:32

标签: haskell lenses

我想实现一些具有一组通用参数的算法(实际上这是一个很高的数字,这就是为什么我不将它们分别传递给函数):

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

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

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

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

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

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

我可以继续使用类型类

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

然后单独实施

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

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

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

2 个答案:

答案 0 :(得分:1)

您要找的是来自Control.Lens.TH的{​​{3}}。阅读有关字段名称假设的文档。 (如果您无法更改字段名称以便与查看好友makeClassyFormakeClassy_

相匹配

这里的想法是模板创建了一类具有commonParameters的东西,并将您的数据结构添加为该类的实例。当许多数据结构具有相同的字段时,它们都将属于同一个类。然后,您可以在镜头存取器中使用该类。

作为一个编程笔记,我倾向于使用 commonParameters和一个合理的名称来创建一个通用结构,所以我可以使用{{1}来引用TH创建的类惯例。

答案 1 :(得分:1)

经典镜片/光学技术在这里很有用。

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

makeClassy模板Haskell指令将产生以下类和实例:

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