7

Could anyone give me suggestions/advice on making type level integers in OCaml (3.12) supporting addition and subtraction operations on them?

For example, if I have numbers represented like this:

type zero
type 'a succ
type pos1 = zero succ
type pos2 =  zero succ succ
...

I need a way to define function on types like this:

val add: pos2 -> pos1 -> pos3

Little background: I'm trying to port some haskell code for operations on physical dimensions and i need the ability to define operations on dimension types (record of 7 type level ints representing exponents of 7 basic SI units). I need to do it this way to avoid dynamic binding (when using objects) and to enable compiler to evaluate and check all such expressions statically.

My current understanding is that I should make a GADT that implements operations as type constructors, but still I'm struggling with the idea, and any hint would be greatly appreciated.

etaoin
  • 81
  • 1
  • 5

3 Answers3

5

You may also be interested in the article Many Holes in Hindley-Milner, by Sam Lindley, from the 2008 Workshop on ML.

Pascal Cuoq
  • 79,187
  • 7
  • 161
  • 281
  • I just looked at these slides; the idea is very simple and cool. However it seems to me it only handles type-level addition. I don't see a way to make it work for subtraction while keeping the simplicity. If you're tracking SI units, I imagine you need subtraction (and negative integers). – Jeffrey Scofield Aug 31 '11 at 19:09
  • @Jeffrey I apologize for ideas coming to me so slowly, but you do know there is a "GADT" branch to OCaml, right? https://sites.google.com/site/ocamlgadt/ (apparently, according to that page, we're getting them with 3.13). – Pascal Cuoq Aug 31 '11 at 19:21
  • 1
    Yes, I've heard rumors of "native" GADT coming to OCaml in 3.13, it's going to be pretty interesting times. I think maybe the OP (etaion) wants to get something working with the current release, but maybe the GADT branch would be acceptable. Dimensional analysis seems like a possibly good test case for GADT. (I'd personally love to see some example GADT code that's not an interpreter for a small language.) Regards, – Jeffrey Scofield Aug 31 '11 at 19:55
  • This is great, thank you Pascal! I haven't yet figured out negative numbers completely, but since the range will be quite limited, current idea is to shift zero (i.e. to 4 to support [-3..3]). I hesitated with trying ocamlgadt branch, since it needs to compile on qnx, and everything needs to be as stable as possible. Also, i didn't find any release date plans for 3.13, so i'm sticking with 3.12 for now. – etaoin Aug 31 '11 at 21:08
  • Thanks once again, i finally tested this out and it works perfectly. As for negative numbers, the trick was to apply successor to the first element of 'difference type pair' (e.g -1 is (z s * z)). After writing negate function (swap, practically) normal addition worked with negatives just fine. – etaoin Sep 04 '11 at 21:27
  • @etaoin This was the most fun presentation that year at the ML workshop (indeed, perhaps at the entire conference). I didn't think it had practical value, too. Glad to hear it helped. – Pascal Cuoq Sep 04 '11 at 22:08
3

You might be able to use one of Oleg's many amazing constructions: http://caml.inria.fr/pub/ml-archives/caml-list/2009/07/2984f23799f442d0579faacbf4e6e904.en.html

Jane Street has another suggestion using first-class modules.

http://ocaml.janestreet.com/?q=node/81

Disclaimer: I mostly admire this kind of programming from afar.

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • Thanks, i hear what you say, but in haskell it all seamed so easy with type classes and what not :) And these links you posted, i've been looking at them all the time, trying to get the essence of it, but never succeeded in bending those modules to my needs. I don't get those type equality constraints they implement, why are they so important and how exactly to use them in achieving "higher kinded" functions? Guess i'll reread them few more times... – etaoin Aug 30 '11 at 18:27
0

Your example makes me think you are trying to do prolog style logic numbers which would be something like

type fancyInt = Zero | Succ of fancyInt ;;

then add would be

let rec add a b = match a with Zero -> b | Succ c -> add c (Succ b);;

Your background story hints at a different solution, create a class that represents distances. Internally store the value however you need to then provide an interface that allows you to get and set the distance in the units necessary at the time. Or if you are wanting to stay with a functional approach just create the types for your units then have of functions the same way Ocaml itself handles such things, i.e. meters_of_km.

stonemetal
  • 6,111
  • 23
  • 25
  • He wants the type and function you give, but at the *type* level. I.e., the type becomes a family (set) of types and your values Zero and Succ become types. And the function add becomes a type-level function, which in OCaml is a parameterized type I guess(?). This kind of thing is done in Haskell all the time. I haven't seen it in OCaml, which suggests it might not be so easy. – Jeffrey Scofield Aug 30 '11 at 17:14
  • Thank you stonemetal, but like Jeffrey said, i need this to happen at type level, so that compiler can execute those operations at compile time and type checker to check the constraints. The idea is to avoid runtime checks which might fail, depending on circumstances when executed (i.e. catch semantically illegal operation, like adding time to length (not intended to support relativity, just plain old Newtonian physics), whereas dividing length by time should be legal and result in new type - for velocity). – etaoin Aug 30 '11 at 18:21
  • Sorry, my higher order type programming abilities are not that great. I would probably fall back to OO, build classes that represent the various kinds of things you need. – stonemetal Aug 30 '11 at 18:36