I'm learning OCaml, from a little bit of Haskell that I studied for my thesis, and I'm wondering if there is a similar mechanism (type classes) to expresses that two numbers are addable (like a generic for int, float, string, etc). I know that in OCaml type classes don't exist but I'm wondering for similar mechanism to express the same thing

I'm trying to make a module type that have the common "method" add, but without success.

``````module type Addable = sig
type t
val add : t -> t -> t
val zero : t
val one : t
end

type t = int
let add a b = a + b
let zero = 0
let one = 1
end

type t = float
let add a b = a +. b
let zero = 0.
let one = 1.
end

let rec sum (type a) (module A : Addable with type t = a) =
match l with
| [] -> A.zero
| x::l -> A.add x (sum (module A) l)
``````

Update: The function sum give an error: "This expression has type 'a but an expression was expected of type a The type constructor a would escape its scope"

Update-Update:

``````module type NumberType = sig
type t
val add : t -> t -> t
val zero : t
val one : t
end

module IntNumber : NumberType with type t = int = struct
type t = int
let add x y = x + y
let zero = 0
let one = 1
end

module FloatNumber : NumberType with type t = float = struct
type t = float
let add x y = x +. y
let zero = 0.0
let one = 1.0
end

module Addbl (M: NumberType) = struct
type t = M.t
let zero = M.zero
let one = M.one
end

let rec sum : type a. (module NumberType with type t = a) -> a list -> a =
fun (module M) l ->
match l with
| [] -> M.zero
| x::t -> M.add x (sum (module M) t)

let () =
let xs = [1.;2.;3.] in
let _ = print_float @@ sum (module FloatNumber) xs in
let _ = print_string "\n" in
let xsi = [1;2;3;4] in
print_int @@ sum (module IntNumber) xsi
``````

This code work and the sum function is generalized. I don't know if there is a way to eliminate the need to pass (module IntNumber) or (module FloatNumber) in the sum function, to abstract this behaviour

Solution

• No, OCaml does not have type classes.

But, consider the `Float` and `Int` modules both implement several common functions, like `add`, `sub`, `mul`, `div`, etc.

They also both have a type `t` and implement these functions in terms of `t`. This allows for a functor to abstract out these behaviors and work much the same way.

``````# module type NumberType = sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end

module Math (N : NumberType) = struct
type t = N.t
let ( + ) = N.add
let ( - ) = N.sub
let ( * ) = N.mul
let ( / ) = N.div
end;;
module type NumberType =
sig
type t
val add : t -> t -> t
val sub : t -> t -> t
val mul : t -> t -> t
val div : t -> t -> t
end
module Math :
functor (N : NumberType) ->
sig
type t = N.t
val ( + ) : t -> t -> t
val ( - ) : t -> t -> t
val ( * ) : t -> t -> t
val ( / ) : t -> t -> t
end
# let open Math (Int) in
45 + 67;;
- : int = 112
# let open Math (Float) in
45.6 + 87.2;;
- : float = 132.8
``````

An example with an `Addable` type using functors:

``````# module type Addable = sig
type t
val nil : t
val add : t -> t -> t
end;;
sig type t val nil : t val add : t -> t -> t end
# module SumList (A : Addable) = struct
type t = A.t
let sum_list = List.fold_left A.add A.nil
end;;
module SumList :
sig type t = A.t val sum_list : t list -> t end
# let open SumList (struct include Int let nil = 0 end) in
sum_list [1; 2; 3; 4];;
- : int = 10
# let open SumList (struct
include String
let nil = ""
end) in
sum_list ["foo"; "bar"; "baz"];;
- : string = "foobarbaz"
``````

You might also use the same `Addable` module signature with first class modules to avoid the need for the functors, allowing one function to sum lists of different types.

``````# let sum_list
(type a)
(module A : Addable with type t = a)
(lst : a list) =
val sum_list : (module Addable with type t = 'a) -> 'a list -> 'a = <fun>
type t = int
let nil = 0
end;;
module IntAdd : sig type t = int val nil : t val add : t -> t -> t end
type t = string
let nil = ""
end;;
module StringAdd : sig type t = string val nil : t val add : t -> t -> t end