haskell - 类子类结构的设计模式
问题描述
我的目标是以优雅和高性能的方式表示一组具有相似行为的类型。为了实现这一点,我创建了一个使用单一类型的解决方案,然后是一组执行模式匹配的函数。
我的第一个问题是:有没有办法如何使用单个类型类来表示相同的想法,而不是每个变体都有一个构造函数来拥有一个实现所述类型类的类型?
以下两种方法中的哪一种是: - Haskell 中更好地识别的设计模式?- 内存效率更高?- 性能更高?- 更优雅,为什么?- 代码的消费者更容易使用?
方法一:单一类型和模式匹配
假设有以下结构:
data Aggregate a
= Average <some necessary state keeping>
| Variance <some necessary state keeping>
| Quantile a <some necessary state keeping>
它的构造函数不是公开的,因为这会暴露内部状态保持。相反,存在一组构造函数:
newAverage :: Floating a
=> Aggregate a
newAverage = Average ...
newVariance :: Floating a
=> Aggregate a
newVariance = Variance ...
newQuantile :: Floating a
=> a -- ! important, a parameter to the function
-> Aggregate a
newQuantile p = Quantile p ...
创建对象后,我们可以执行两个功能:put
将值放入其中,一旦我们满意,我们就可以get
获取当前值:
get :: Floating a
=> Aggregate a
-> Maybe a
get (Average <state>) = getAverage <state>
get (Variance <state>) = getVariance <state>
get (Quantile _ <state>) = getQuantile <state>
put :: Floating a
=> a
-> Aggregate a
-> Aggregate a
put newVal (Average <state>) = putAverage newVal <state>
put newVal (Variance <state>) = putVariance newVal <state>
put newVal (Quantile p <state>) = putQuantile newVal p <state>
方法 2:类型类和实例
class Aggregate a where
new :: a
get :: Floating f => a f -> Maybe f
put :: Floating f =>
data Average a = Average Word64 a
data Variance a ...
instance Aggregate Average where
instance Aggregate Variance where
instance Aggregate Quantile where
这里明显的问题是它new
不是参数化的,因此Quantile
不能用p
参数初始化。添加参数new
是可能的,但它会导致所有其他非参数构造函数忽略该值,这不是一个好的设计。
解决方案
您缺少“codata”编码,这听起来可能最适合您的问题。
data Aggregate a = Aggregate
{ get :: Maybe a
, put :: a -> Aggregate a
}
-- Use the closure to keep track of local state.
newAverage :: (Floating a) => Aggregate a
newAverage = Aggregate { get = Nothing, put = go 0 0 }
where
go n total x = Aggregate { get = Just ((total + x) / (n+1))
, put = go (n+1) (total+x)
}
-- Parameters are not a problem.
newQuantile :: (Floating a) => a -> Aggregate a
newQuantile p = Aggregate { get = ... ; put = \x -> ... }
...
出于某种原因,这种方法总是在具有 OO 背景的人的雷达下溜走,这很奇怪,因为它与该范式非常接近。
推荐阅读
- php - 如何使用 html 表单从 php 文件中加载和编辑所有字符串
- javascript - 悬停在highchart的同步图表上时线褪色
- react-redux - React -Redux:如何在提交事件上调度操作时将文本框值作为参数传递给调度方法
- python - 从具有多个值(〜500 000)的熊猫数据框创建数组的最快方法
- powershell - PowerShell If 语句失败
- java - 如何修复与语义谓词一起使用的左递归中的错误?
- d3.js - 条形图上的平均线
- java - 用于捕获特殊字符的正则表达式
- firebase - 使用actions-sdk的dialogflow环聊聊天集成无响应
- excel - 创建没有编译错误消息的目录