如何在F#中编写代码,以了解OCaml中的函子? [英] How to write code in F# for what functors do in OCaml?

查看:71
本文介绍了如何在F#中编写代码,以了解OCaml中的函子?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有许多用OCaml编写的程序,其中一些使用函子.现在,我正在考虑编写和重写F#中的一部分代码(以受益于OCaml不具备的某些优势).我担心的一件事是用F#编写代码,了解函子在OCaml中的作用.

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 does not have). One thing I am afraid of is to write code in F# for what functors do in OCaml.

例如,我们如何在F#中模拟此示例来自OCaml手册?

For instance, how could we emulate this example from OCaml manual in F#?

type comparison = Less | Equal | Greater

module type ORDERED_TYPE = sig
  type t
  val compare: t -> t -> comparison
end

module Set =
functor (Elt: ORDERED_TYPE) -> struct
    type element = Elt.t
    type set = element list
    let empty = []
    let rec add x s =
      match s with
        [] -> [x]
      | hd::tl ->
         match Elt.compare x 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
  end

module OrderedString = struct
  type t = string
  let compare x y = if x = y then Equal else if x < y then Less else Greater
end

module OrderedInt = struct
  type t = int
  let compare x y = if x = y then Equal else if x < y then Less else Greater
end

module StringSet = Set(OrderedString)
module IntSet = Set(OrderedInt)

let try1 () = StringSet.add "foo" StringSet.empty
let try2 () = IntSet.add 2 IntSet.empty

推荐答案

您已经注意到,F#没有函子-无法通过类型对F#模块进行参数化.使用该语言的面向对象部分-接口,泛型类和继承,可以在F#中获得类似的结果.

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<string, Ordered<string>>
type IntSet = Set<int, Ordered<int>>

let try1 () = Set.add "foo" StringSet.Empty
let try2 () = Set.add 2 IntSet.Empty

try1().Values
try2().Values

这篇关于如何在F#中编写代码,以了解OCaml中的函子?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆