jor*_*gen 2 haskell default class repeat subclassing
我对haskell很新,我认为我陷入了一些OO陷阱.这是一个结构(简化)的草图,我在实施时遇到了麻烦:
Observable的一个概念,它作用于样本列表(Int)以产生结果(Int)
一个函数实例,例如一个平均值乘以常数的函数实例
我的第一个想法是使用一个子类; 类似的东西(以下是有点人为但有希望得到的想法)
class Observable a where
estimate :: a -> [Int] -> Int
class (Observable a) => SimpleObservable a where
compute :: a -> Int -> Int
simpleEstimate :: a -> [Int] -> Int
simpleEstimate obs list = sum $ map compute list
data AveConst = AveConst Int
instance Observable AveConst where
estimate = simpleEstimate
instance SimpleObservable AveConst where
compute (AveConst c) x = c * x
Run Code Online (Sandbox Code Playgroud)
然而,即使像上面这样的东西编译它是丑陋的.谷歌搜索告诉我DefaultSignatures可能会有所帮助,因为我没有必要estimate = simpleEstimate为每个实例做些事情,但是从围绕它的讨论来看,这样做似乎是反模式.
另一种选择是没有子类,但是(具有相同的Observable类):
data AveConst = AveConst Int
instance Observable AveConst where
estimate (AveConst c) list = sum $ map (*c) list
Run Code Online (Sandbox Code Playgroud)
但是这种方式我不确定如何重用模式; 每个Observable都必须包含完整的estimate定义,并且会有代码重复.
第三种方式是具有函数字段的类型:
data SimpleObservable = SimpleObservable {
compute :: [Int] -> Int
}
instance Observable SimpleObservable where
estimate obs list =
sum $ map (compute obs) list
aveConst :: Int -> SimpleObservable
aveConst c = SimpleObservable {
compute = (*c)
}
Run Code Online (Sandbox Code Playgroud)
但我不确定这是否也是惯用的.有什么建议?
我建议更简单:
type Observable = [Int] -> Int
Run Code Online (Sandbox Code Playgroud)
然后,平均可观察量是:
average :: Observable
average ns = sum ns `div` length ns
Run Code Online (Sandbox Code Playgroud)
如果你Observable需要一些内部数据 - 比如一个常数来乘以 - 没问题; 这就是闭包的用途.例如:
sumTimesConst :: Int -> Observable
sumTimesConst c = sum . map (c*)
Run Code Online (Sandbox Code Playgroud)
你可以Observable毫无困难地抽象出构造s; 例如,如果你想要SimpleObservable只查看元素,然后求和,你可以:
type SimpleObservable = Int -> Int
timesConst :: Int -> SimpleObservable
timesConst = (*)
liftSimple :: SimpleObservable -> Observable
liftSimple f = sum . map f
Run Code Online (Sandbox Code Playgroud)
然后liftSimple . timesConst是另一个完美的拼写方式sumTimesConst.
......但说实话,上述任何事情我都会觉得很脏.sum . map (c*)是一个完全可读的表达式,没有为其类型引入可疑的新名称.