It will eventually, when someone fixes Zarith…
@Drup has written a ppx for that, but you’ll have to wait a little bit before having this merged and pushed in opam (see the PR for more information).
About the use of functor and mixing Zarith and Num, the problem is that they don’t have the same interface, so you first have to implement your own module (based on Num) with an interface similar to the one of Zarith. For simplicity, and the running example, I’ll use:
module type Arith = sig
type t
val (+) : t -> t -> t
val (-) : t -> t -> t
val ( * ) : t -> t -> t
val (/) : t -> t -> t
val (//) : int -> int -> t
val to_float : t -> float
end
(* an Arith module based on Num *)
module Mynum : Arith with type t = Num.num = struct
open Num
type t = num
let (+) = add_num
let (-) = sub_num
let ( * ) = mult_num
let (/) = div_num
let (//) i j = num_of_int i / num_of_int j
let to_float = float_of_num
end
then you can write code parameterized by an Arith module:
module F (A : Arith) = struct
open A
let r = 102//10 - 24//10
let r' = to_float r
end
and test it in the REPL:
(* load needed modules *)
#require "num-top";;
#require "zarith";;
#install_printer Q.pp_print;;
(* test the functor *)
let module R = F (Q) in R.r;;
- : Q.t = 39/5
let module R = F (Q) in R.r';;
- : float = 7.8
let module R = F (Mynum) in R.r;;
- : Mynum.t = <num 39/5>
let module R = F (Mynum) in R.r';;
- : float = 7.8
Or, alternatively, you can use first-class modules and use usual functions:
let f_r (type a) (module A : Arith with type t = a) =
A.(102//10 - 24//10)
let f_r' (module A : Arith) = A.to_float @@ f_r (module A)
and to test in the REPL:
f_r (module Q);;
- : Q.t = 39/5
f_r' (module Q);;
- : float = 7.8
f_r (module Mynum);;
- : Mynum.t = <num 39/5>
f_r' (module Mynum);;
- : float = 7.8
Thank you, that’s incredibly helpful!
The next release of ZArith should define a package zarith.top
so that #require zarith.top
install printers in the REPL.
UPDATE: this got fixed when I added type t = A.t
to my implementation
I used this advice to write my own module like:
module Number (A : Arith) = struct
open A
type t = A.t (* this fixed the problem *)
let from_ast {Ast.numerator; Ast.denominator} = numerator // denominator
end
Then I tried using the type to construct composite types, but the compiler refuses it with error
Unbound type constructor Number.t
module Number = Lklmath.Number (Q)
type currency_value = (Number.t * currency)
What am I missing? Is it possible to do what I want?