Haskell与OOP中的抽象类对象列表相对应

时间:2018-08-11 08:06:55

标签: haskell functional-programming

我正在学习Haskell,遇到了这个问题。 不使用现有类型,我们如何将以下OOP伪代码转换为Haskell?不是在Haskell中模拟OOP概念的方法,而是正确的Haskell方法。

    x = 23

    i = 1
    while i <= x:
      if x % i == 0:
        print("factor: %s"% i)
      i += 1

我的想法之一是,我们不使用类型类,而只是将class MetricQuery { ... } abstract class Metric[T] { def computeValue(q: MetricQuery): T } class LinkClicksMetric extends Metric[Int] { ... } class ButtonClicksMetric extends Metric[Int] { ... } class PostCommentsMetric extends Metric[Int] { ... } ... query: MetricQuery = ... metrics: List[Metric[Int]] = ... results: List[Int] = metrics.map(\x -> x.computeValue(query)) 函数设为Haskell数据类型的字段:

computeValue

我认为这可行,只是不确定这是否是“适当的” Haskell方法。

此外,我不知道如何使用特定指标存储其他数据(即,OO术语中的成员变量)。我尝试使用状态类型对度量标准类型构造函数进行参数化,但这导致了不同的特定度量标准类型(例如data MetricQuery = ... data Metric a = Metric { computeValue :: MetricQuery -> a } linkClicksMetric :: Metric Int linkClicksMetric = Metric { computeValue = \q -> ... } buttonClicksMetric :: Metric Int buttonClicksMetric = Metric { computeValue = \q -> ... } results = let query = ... metrics = ... in fmap (\x -> computeValue x query) metrics Metric Int State1)。一种想法是将Metric Int State1设置为data MetricState = ... | ... | ...的字段,以便每个特定指标都可以定义自己的状态类型。

1 个答案:

答案 0 :(得分:4)

您的Metric数据类型可能会更好,因为它只是类型的同义词。

Metric a = MetricQuery -> a

如果您的特定指标包含其他信息,那么获取此信息的一种方法是部分应用:

buttonClicksMetric :: Button -> Metric Int
buttonClicksMetric button query = ....

之所以可行,是因为通过替换类型同义词,您可以将类型读取为

buttonClicksMetric :: Button -> MetricQuery -> Int

因此,现在您可以通过将Metric Int传递到Button来创建buttonClicksMetric。同样,您可以使用Metric Int创建另一个linkClicksMetric并将它们都放在列表中。

但是,如果您想使用buttonClicksMetric进行其他操作,这些操作需要访问按钮,例如显示按钮。然后,您需要一种数据类型(此设计模式通常称为函数的“验证”:

newtype ButtonClicksMetric = ButtonClicksMetric {getButton :: Button}

(除了:newtype的工作原理与data几乎完全相同,不同之处在于您只能具有一个字段和一个构造函数,并且运行时成本为零。底部语义有一些细微的差异不需要担心的值。如果在ButtonClicksMetric中需要更多字段,则可以使用data。)

buttonClicksMetric的类型现在变为

buttonClicksMetric :: ButtonClicksMetric -> Metric Int

其他所有功能都一​​样。