1

I am writing a small script with some combinatorics utilities. When I need a numeric literal like 0 or 1 in a different type, I use _0 and _1, but this solution is less than ideal. Is it possible to use Camlp4 to reinterpret numeric literals within a given context or add a new type of numeric literal with a dedicated suffix?

open Num
let zero = num_of_int 0
let one = num_of_int 1
let _0 = zero
let _1 = one

(* some useful infix operators *)
let ( + ) = ( +/ )
let ( - ) = ( -/ )
let ( * ) = ( */ )
let ( < ) = ( </ )
let ( > ) = ( >/ )
let ( = ) = ( =/ )
let ( / ) numer denom = 
    if mod_num numer denom = _0
    then div_num numer denom
    else invalid_arg "division is not a total function"

(* factorial, naive *)
let rec fact n =
    if n < _0
    then invalid_arg "negative factorial"
    else if n = _0
    then _1
    else
        n * fact (n - _1)

(* naive algorithm *)
let choose n k = (fact n / fact k) / fact (n - k)
objmagic
  • 1,028
  • 1
  • 9
  • 18
Greg Nisbet
  • 6,710
  • 3
  • 25
  • 65
  • With Num open you can write `let i = Int 4` wich is not very cumbersome. And the trick with defining numbers zero, one and two can be seen quite often in code. – Str. Dec 24 '15 at 17:05

2 Answers2

1

In short, no. Camlp4 is preprocessor of untyped parse tree. It cannot do such type sensitive thing.

If you would want (and I bet you will not), you can run type checking against the untyped parse trees in Camlp4 and infer the types of your special numerals, then replace them by corresponding values. It is theoretically possible but none has ever tried it, since P4's parse tree is completely different from the one of OCaml.

PPX preprocessor, which is meant to replace Campl4, has some hope, since it handles the same untyped parse tree as OCaml and therefore it is easy to apply OCaml type checker. TyPPX (https://bitbucket.org/camlspotter/typpx) is such a framework to provide APIs for type dependent preprocessing.

camlspotter
  • 8,990
  • 23
  • 27
1

You may want to have a look to delimited overloading — it requires to qualify your constants by surrounding the expression e with M.(e) where M is the name of your module (you can define aliases).

ChriS
  • 606
  • 3
  • 6
  • I've read about delimited overloading before, but am somewhat confused about how to use it in a project. Do you have to include the extension as a compiler flag? Is there a way to include a directive in your source so that compilation will fail in a predictable way if the extension is not present and top levels like `utop` will load it automatically? – Greg Nisbet Dec 24 '15 at 18:12