我的目标是以优雅和高效的方式表示一组具有相似行为的类型。为实现此目的,我创建了一个使用单一类型的解决方案,然后使用了一组执行模式匹配的函数。
我的第一个问题是:有一种方法可以使用单个类型类来表示相同的想法,而不是每个变体都具有一个构造函数来实现该类型类的类型?
以下两种方法中的哪一种是:-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>
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
添加参数是可能的,但是这将导致所有其他非参数构造函数忽略该值,这不是一个好的设计。
很难给出一般性建议。我倾向于使用方法1。请注意,您可以使用
data Aggregate a
= Average AverageState
| Variance VarianceState
| Quantile a QuantileState
并导出上面的每个构造函数,仅将...State
类型保留为模块专用。
[在某些情况下可能可行,但在其他情况下则不可行,因此必须根据具体情况进行评估。
关于方法2,如果周围有很多构造函数/类型,这可能会更方便。要解决new
问题,可以使用[
class Floating f => Aggregate a f where
type AggregateNew a f
new :: AggregateNew a f -> a f
get :: a f -> Maybe f
put :: ...
instance Floating f => Aggregate Average f where
type AggregateNew (Average a) f = ()
new () = ...
instance Aggregate Quantile where
type AggregateNew (Quantile a) f = a
new x = ...