以常见方式作为实例的一组函数

jor*_*gen 2 haskell default class repeat subclassing

我对haskell很新,我认为我陷入了一些OO陷阱.这是一个结构(简化)的草图,我在实施时遇到了麻烦:

  • Observable的一个概念,它作用于样本列表(Int)以产生结果(Int)

    • 使用某种模式实现结果的SimpleObservable概念(虽然会有Observables以其他方式执行),例如平均值
  • 一个函数实例,例如一个平均值乘以常数的函数实例

我的第一个想法是使用一个子类; 类似的东西(以下是有点人为但有希望得到的想法)

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)

但我不确定这是否也是惯用的.有什么建议?

Dan*_*ner 5

我建议更简单:

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*)是一个完全可读的表达式,没有为其类型引入可疑的新名称.