Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

int * int vs (int * int) in OCaml sum type

Tags:

ocaml

type foo = A of int * int | B of (int * int)

What is the difference between int * int and (int * int) there? The only difference I see is in pattern matching:

let test_foo = function
  | A (f, s) -> (f, s)
  | B b -> b

Is it just a syntactic sugar? How do you select which one to use? Is there any performance difference between these two forms?

like image 390
Stas Avatar asked Feb 11 '13 18:02

Stas


People also ask

What does asterisk mean in OCaml?

The * symbol is used to separate elements of a tuple in data type definitions.

What is int in OCaml?

The type for integer values. val zero : int. zero is the integer 0 . val one : int.

What does |> do in OCaml?

The |> operator represents reverse function application.


2 Answers

Yes, there is a performance difference:

In memory A (23, 42) will contain a tag identifying it as an A and the two integers 23 and 42. B (23, 42) will contain a tag identifying it as a B and a pointer to a tuple containing the integers 23 and 42. So there will be one additional memory allocation when creating a B and one additional level of indirection when accessing the individual values inside a B. So in cases where you don't actually use the constructor arguments as a tuple, using A will involve less overhead than using B.

On the other hand your test_foo function will create a new tuple every time it is called with an A value, but when it is called with a B value it will simply return the tuple that already exists in memory. So test_foo is a cheaper operation for B than it is for A. So if you'll be using the constructor's arguments as a tuple and you will do so multiple times for the same value, using B will be cheaper.

So if you're going to be using the constructor arguments as a tuple, it makes sense to use a constructor taking a tuple because you can get at the tuple using pattern matching with less code and because it will avoid having to create tuples from the same value multiple times. In all other cases not using a tuple is preferable because it involves less memory allocation and less indirection.

like image 90
sepp2k Avatar answered Sep 27 '22 17:09

sepp2k


As already said, the constructor of A takes two int, whereas the constructor of B takes an ordered pair.

so you can write

let bar = A (1, 2)

or

let bar = B (1, 2)

or

let bar = (1, 2)
let baz = B bar

but you cannot write

let bar = (1, 2)
let baz = A bar

Moreover, in your pattern matching, you can still match the content of B as two int, but you cannot match the content of A as value bound to an ordered pair

let test_foo = function
  | A a -> a (* wrong *)
  | B (f, s) -> (f, s) (* ok *)
like image 37
Benoît Guédas Avatar answered Sep 27 '22 16:09

Benoît Guédas