我想实现一些具有一组通用参数的算法(实际上这是一个很高的数字,这就是为什么我不将它们分别传递给函数):
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'
信息量不大)。
有没有更简单的方法来解决这个问题?。
答案 0 :(得分:1)
您要找的是来自Control.Lens.TH
的{{3}}。阅读有关字段名称假设的文档。 (如果您无法更改字段名称以便与查看好友makeClassyFor
和makeClassy_
)
这里的想法是模板创建了一类具有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