tags:

views:

124

answers:

3

I want nice operators for complex arithmetic to make my code more readable. Ocaml has a Complex module, so I just want to add operators that call those functions.

The most intuitive way for me is to make a new complex operator from all of the usual operators by appending '&' to the operator symbol. Thus +& and *& will be complex addition and multiplication. I would also like ~& to be complex conjugation.

If I'm going to use these operators, I want them to associate the same way that normal arithmetic associates. Based on the following sessions, they are automatically behaving the way I want, but I would like to understand why, so that I don't get horrible bugs when I introduce more operators.

My current guess is that their precedence is done by lexically sorting the operator symbols according to an ordering that is consistent with normal arithmetic precedence. But I cannot confirm this.

Session one:

# open Complex;;
# let (+&) a b = add a b;;
val ( +& ) : Complex.t -> Complex.t -> Complex.t = <fun>
# let ( *&) a b = mul a b;;
val ( *& ) : Complex.t -> Complex.t -> Complex.t = <fun>
# one +& zero *& one +& zero *& one;;
- : Complex.t = {re = 1.; im = 0.}
# zero +& one *& zero +& one *& zero;;
- : Complex.t = {re = 0.; im = 0.}
# i +& i *& i +& i *& i *& i;;
- : Complex.t = {re = -1.; im = 0.}

Session two:

# open Complex;;
# let ( *&) a b = mul a b;;
val ( *& ) : Complex.t -> Complex.t -> Complex.t = <fun>
# let (+&) a b = add a b;;
val ( +& ) : Complex.t -> Complex.t -> Complex.t = <fun>
# one +& zero *& one +& zero *& one;;
- : Complex.t = {re = 1.; im = 0.}
# zero +& one *& zero +& one *& zero;;
- : Complex.t = {re = 0.; im = 0.}
# i +& i *& i +& i *& i *& i;;
- : Complex.t = {re = -1.; im = 0.}
# let (~&) a = conj a;;
val ( ~& ) : Complex.t -> Complex.t = <fun>
# (one +& i) *& ~& (one +& i);;
- : Complex.t = {re = 2.; im = 0.}
+8  A: 

In general, the associativity and precedence of an operator (unless you go out to camlp4 or something) is based on the operator's first character.

source (look for for "Associativity precedence for the user-defined operator").

There is no way to define it explicitly in OCaml (see this and also "User-defined infix operators" on Comparing Objective Caml and Standard ML)

You can use camlp4 or camlp5 to explicitly define the order of infix function. It seems like pa_do can also be an option.

I tried to write an example but I am not familiar with camlp4 and it is not easy to learn in a few minutes.

dbarbosa
Thanks! I'm sort of annoyed that the correct answer is not more useful and/or awesome. I too am not familiar enough with p4/p5 to use it.
forefinger
Great link(s). I was going to mention camlp{4,5}, but fixing the precedence of operators was only a mean in the original question. The end was to make the code future-proof. I doubt any solution involving camlp{4,5} is a good solution towards this goal; it is certainly a dependency I try to avoid, although it is often tempting.
Pascal Cuoq
+7  A: 

It's right in the OCaml manual, section 6.7, scroll down, right before section 6.7.1. The precedence table has some things like +..., which includes any user-defined starting with +. It is not true that it always depends on the first character, as **... has higher precedence than *....

newacct
+2  A: 

The pa-do syntax extension for OCaml addresses exactly this issue:

http://pa-do.forge.ocamlcore.org/

You can use it to change operator precedence, or, more usefully in this case, use explicit context to change the meaning of operators.

hcarty