8

F# 是带有 OOP 的 ML。与 Haskell 广义代数数据类型和类型类最接近的是什么?

4

2 回答 2

19

答案取决于您要解决的问题。F# 没有类型类和 GADT,因此没有直接映射。但是,F# 有多种机制可以用来解决通常在 Haskell 中使用 GADT 和类型类解决的问题:

  • 如果您想表示对象结构并能够添加具有不同行为的新具体实现,那么您通常可以使用标准的 OO 和接口。

  • 如果您想编写通用数字代码,您可以使用静态成员约束(这里是一个示例),这在技术上可能是最接近类型类的机制。

  • 如果您想编写更高级的通用代码(如通用打印机或解析器),那么您通常可以使用强大的 F# 运行时反射功能。

  • 如果您需要通过一组函数(执行代码所需的各种子操作)参数化代码,那么您可以传递接口的实现,如@pad 所示。

还有一种方法可以在 F# 中模拟 Haskell 类型类,但这通常不是 F# 惯用的解决方案,因为 F# 编程风格在很多方面与 Haskell 风格不同。一个相当标准的用法是定义重载运算符(请参阅this SO answer)。

在元层面上,问什么是另一种语言中的特征 X 的等价物通常会导致讨论混乱,因为 X 可能用于解决一种语言中的问题 A、B、C,而另一种语言可能提供不同的特征来解决相同的问题(或某些问题可能根本不存在)。

于 2012-11-09T16:04:45.183 回答
7

在 F# 中,您经常将接口继承用于这些目的。

举例来说,这是一个使用接口和对象表达式的简单类型类:

/// Typeclass
type MathOps<'T> =
    abstract member Add : 'T -> 'T -> 'T
    abstract member Mul : 'T -> 'T -> 'T

/// An instance for int
let mathInt = 
    { new MathOps<int> with
       member __.Add x y = x + y
       member __.Mul x y = x * y }

/// An instance for float
let mathFloat = 
    { new MathOps<float> with
       member __.Add x y = x + y
       member __.Mul x y = x * y }

let XtimesYplusZ (ops: MathOps<'T>) x y z =
    ops.Add (ops.Mul x y) z

printfn "%d" (XtimesYplusZ mathInt 3 4 1)
printfn "%f" (XtimesYplusZ mathFloat 3.0 4.0 1.0)

它可能看起来不是很漂亮,但它是 F#-ish 的方式。对于使用操作字典的更类似于 Haskell 的解决方案,您可以查看这个不错的答案

于 2012-11-09T16:11:00.997 回答