How to use different libraries depending on the environment? How to use rationals?

It will eventually, when someone fixes Zarith

1 Like

@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
3 Likes

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.

1 Like

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?