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?
The * symbol is used to separate elements of a tuple in data type definitions.
The type for integer values. val zero : int. zero is the integer 0 . val one : int.
The |> operator represents reverse function application.
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.
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 *)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With