How to write code in F# for what functors do in OCaml?

后端 未结 3 2254
一个人的身影
一个人的身影 2021-02-19 19:21

I have many programs written in OCaml, some of them use functors. Now, I am considering of writing and re-writing a part of code in F# (to benefit some advantages that OCaml doe

3条回答
  •  我在风中等你
    2021-02-19 20:23

    As you noticed, F# doesn't have functors - F# modules cannot be parameterized by types. You can get similar results in F# using the object oriented parts of the language - interfaces, generic classes and inheritance.

    Here's a heavy handed approach at emulating your example.

    type Comparison = Less | Equal | Greater
    
    /// Interface corresponding to ORDERED_TYPE signature
    type IOrderedType<'a> = 
        abstract Value: 'a
        abstract Compare: IOrderedType<'a> -> Comparison
    
    /// Type that implements ORDERED_TYPE signature, different instantiations
    /// of this type correspond to your OrderedInt/OrderedString modules.
    /// The 't: comparison constraint comes from the fact that (<) operator 
    /// is used in the body of Compare.
    type Ordered<'t when 't: comparison> (t: 't) =
        interface IOrderedType<'t> with
            member this.Value = t
            member this.Compare (other: IOrderedType<'t>) = 
                if t = other.Value then Equal else if t < other.Value then Less else Greater
    
    /// A generic type that works over instances of IOrderedType interface.
    type Set<'t, 'ot when 't: comparison and 'ot :> IOrderedType<'t>> (coll: IOrderedType<'t> list) =
    
        member this.Values = 
            coll |> List.map (fun x -> x.Value)
    
        member this.Add(x: 't) = 
            let rec add (x: IOrderedType<'t>) s = 
                match coll with
                | [] -> [x]
                | hd::tl ->
                    match x.Compare(hd) with
                    | Equal   -> s         (* x is already in s *)
                    | Less    -> x :: s    (* x is smaller than all elements of s *)
                    | Greater -> hd :: add x tl
            Set<'t, 'ot>(add (Ordered(x)) coll)
    
        static member Empty = Set<'t, 'ot>(List.empty)
    
    /// A helper function for Set.Add. Useful in pipelines. 
    module Set =     
        let add x (s: Set<_,_>) =
           s.Add(x)
    
    /// Type aliases for different instantiations of Set 
    /// (these could have easily been subtypes of Set as well)
    type StringSet = Set>
    type IntSet = Set>
    
    let try1 () = Set.add "foo" StringSet.Empty
    let try2 () = Set.add 2 IntSet.Empty
    
    try1().Values
    try2().Values
    

提交回复
热议问题