What's the closest thing to Haskell GADTs and typeclasses in F#?

后端 未结 2 1023
旧时难觅i
旧时难觅i 2020-12-31 19:32

F# is an ML with OOP. What\'s the closest it comes to Haskell generalized algebraic data types and typeclasses?

相关标签:
2条回答
  • 2020-12-31 20:02

    The answer depends on what problem are you trying to solve. F# does not have typeclasses and GADTs, so there is no direct mapping. However, F# has various mechanisms that you would use to solve problems that you typically solve in Haskell using GADTs and typeclasses:

    • If you want to represent object structures and be able to add new concrete implementations with different behaviour, then you can often use standard OO and interfaces.

    • If you want to write generic numeric code, you can use static member constraints (here is an example), which is probably technically the closest mechanism to type classes.

    • If you want to write more advanced generic code (like universal printer or parser) then you can often use the powerful F# runtime reflection capabilities.

    • If you need to parameterize code by a set of functions (that perform various sub-operations required by the code) then you can pass around an implementation of an interface as @pad shows.

    There is also a way to emulate Haskell type classes in F#, but this is usually not an idiomatic F# solution, because the F# programming style differs from the Haskell style in a number of ways. One fairly standard use of this is defining overloaded operators though (see this SO answer).

    At the meta-level, asking what is an equivalent to a feature X in aother language often leads to a confused discussion, because X might be used to solve problems A, B, C in one language while another language may provide different features to solve the same problems (or some of the problems may not exist at all).

    0 讨论(0)
  • 2020-12-31 20:27

    In F#, you often use interfaces and inheritance for these purposes.

    For examples' sake, here is a simple typeclass using interfaces and 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)
    

    It may not look very beautiful, but it's F#-ish way to do it. For a more Haskell-like solution which uses a dictionary-of-operations, you can have a look at this nice answer.

    0 讨论(0)
提交回复
热议问题