I'm working on a functional programming project. I have encountered a few difficulties, so I will post here a few things that took me quite a while (and a lot of luck) to find. Especially operator overloading, where Google lead me only to endless discussions about wether it should exist or not and why it doesn't, when it actually does.
I will write a code snippet that will allow us to use integers and Big_ints the exact same way, for instance doubling them using one function named "twice". (In other words, putting two and two together with 4 modules and a functor - can something be more fun?)
First, let's get to the Big_ints:
1 #load "nums.cma";;
2 open Big_int;;
So far so good. Now, we'll declare two modules that can add numbers, one for integers, one for the Big_ints, but first, they'll need a signature:
4 module type Add_sig =
5 sig
6 type t;;
7 val (+): t -> t -> t
8 end;;
Now, the modules. Notice how cool functional programming is, you can assign functions like other values:
10 module Int_modl=
11 struct
12 type t = int
13 let (+) = (+);;
14 end;;
15
16 module BigInt_modl =
17 struct
18 type t = big_int
19 let (+) = add_big_int;;
20 end;;
The "let (+) = (+)" looks stupid, but is required.
Now we'll write a functor to transform these two modules in two new modules that have a richer functionality (okay, "twice" is not "rich", but that's just an example and I hope you can see the big picture), that we will implement only once, though int and Big_int are two completely different data types and have completely different additions ("+" and "add_big_int") - again, notice how cool functional programming is.
22 module Add =
23 functor (Modl : Add_sig) ->
24 struct
25 type t = Modl.t
26 let (+) = Modl.(+)
27 let twice t = t + t;;
28 end;;
Nice functor. Let's use it to create the previously mentioned modules and we're almost there:
30 module Ints = Add(Int_modl);;
31 module Bigs = Add(BigInt_modl);;
Okay, time to see if that works:
33 Ints.twice 2;;
34 int_of_big_int (Bigs.twice (big_int_of_int 2));;
We have a bit of hassle with creating and printing the Big_ints (thus the longer code), but in the end, we defined one function "twice" that uses the same operator "+" to perform technically completely different operations (with an emphasis on technically - you could use this technique to make "+" mean subtraction or multiplication for the integers and that would be nasty).
Finally, the entire code, ready to copy, paste and... run!
#load "nums.cma";;
open Big_int;;
module type Add_sig =
sig
type t;;
val (+): t -> t -> t
end;;
module Int_modl=
struct
type t = int
let (+) = (+);;
end;;
module BigInt_modl =
struct
type t = big_int
let (+) = add_big_int;;
end;;
module Add =
functor (Modl : Add_sig) ->
struct
type t = Modl.t
let (+) = Modl.(+)
let twice t = t + t;;
end;;
module Ints = Add(Int_modl);;
module Bigs = Add(BigInt_modl);;
Ints.twice 2;;
int_of_big_int (Bigs.twice (big_int_of_int 2));;