Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

Tags:

functor

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.

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
like image 615
SoftTimur Avatar asked Apr 25 '16 17:04

SoftTimur


1 Answers

Here is a bit different approach that achieves same outcome using a generic class and one object per type.

type Comparison = Less | Equal | Greater

type Set<'a>(compare : 'a -> 'a -> Comparison) =

    member this.Empty : 'a list = []

    member this.Add x s = 
         match s with
         | [] -> [x]
         | hd::tl ->
             match compare x hd with
             | Equal   -> s         (* x is already in s *)
             | Less    -> x :: s    (* x is smaller than all elements of s *)
             | Greater -> hd :: this.Add x tl


let compare x y = if x = y then Equal else if x < y then Less else Greater

let compareFloats (x : float) (y : float) = if x = y then Equal else if x < y then Less else Greater

// Note that same generic compare function can be used for stringSet and intSet
// as long as the type parameter is explicitly given
let stringSet = Set<string>(compare)
let intSet = Set<int>(compare)

// Type parameter not needed, because compareFloats is not generic
let floatSet = Set(compareFloats)

let try1 () = stringSet.Add "foo" stringSet.Empty   // -> ["foo"]
let try2 () = intSet.Add 2 intSet.Empty             // -> [2]
let try3 () = floatSet.Add 3.0 floatSet.Empty       // -> [3.0]
like image 165
hvester Avatar answered Sep 18 '22 06:09

hvester