【问题标题】:What's the closest thing to Haskell GADTs and typeclasses in F#?与 F# 中的 Haskell GADT 和类型类最接近的是什么?
【发布时间】:2012-11-09 15:29:38
【问题描述】:

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

【问题讨论】:

    标签: f# typeclass gadt


    【解决方案1】:

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

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

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

    • 如果您想编写更高级的通用代码(如通用打印机或解析器),通常可以使用powerful F# runtime reflection 功能。

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

      李>

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

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

    【讨论】:

      【解决方案2】:

      在 F# 中,您经常将 interfacesinheritance 用于这些目的。

      为了示例,这里是一个使用接口和object expressions 的简单类型类:

      /// 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 的解决方案,您可以查看 this nice answer

      【讨论】:

      • 这是一个误导性的示例,因为对于数字代码,您只需编写 let inline XtimesYplusZ x y z = (x * y) + zXtimesYplusZ 3 4 1XtimesYplusZ 3.0 4.0 1.0 即可。但是,当然,在不同的场景中,基于您演示的样式的代码将是通过操作对这种参数化进行建模的好方法。我想这就是我的意思是说 Haskell 中的类型类解决的不同问题有不同的方法。
      • 是的,我很难找到一个好的例子。我想展示的只是编码风格;这与数字代码无关。
      • 没听懂。你只是在使用泛型。
      • @LeoCavalcante,这是一篇解释这个想法的 Haskell 文章:haskellforall.com/2012/05/scrap-your-type-classes.html 基本上你可以使用 typeclass-using 签名 (Monad m) => [m a] -> m [a] 并将其转换为一个常规值签名 MonadWitness m -> [m a] -> m [a],并完全绕过类型级编程,只要您愿意显式传入见证。
      猜你喜欢
      • 2020-03-10
      • 2012-01-15
      • 2012-06-10
      • 2021-10-30
      • 1970-01-01
      • 2011-09-25
      • 2013-08-06
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多