In the answers for the tutorials for OCaml available at this site, some of the solutions, including the one for eliminating consecutive duplicates of list elements, is written as such:
let rec compress = function
| a :: (b :: _ as t) -> if a = b then compress t else a :: compress t
| smaller -> smaller;;
What is the relevance of the line a :: (b:: _ as t)
? Why can't I write it as a :: b :: t
instead?
The way -> is defined, a function always takes one argument and returns only one element. A function with multiple parameters can be translated into a sequence of unary functions.
The type 'a is a type variable, and stands for any given type. The reason why sort can apply to lists of any type is that the comparisons (=, <=, etc.) are polymorphic in OCaml: they operate between any two values of the same type. This makes sort itself polymorphic over all list types.
The pattern h :: t matches any non-empty list, calls the head of the list h (one element, the first one), and the tail of the list t (zero or more elements after the first one). The operator :: is the list constructor (often called "cons"), which is why these patterns match lists.
Pattern matching comes up in several places in OCaml: as a powerful control structure combining a multi-armed conditional, unification, data destructuring and variable binding; as a shortcut way of defining functions by case analysis; and as a way of handling exceptions.
The t
in b :: _ as t
is bound to b :: _
. So the meaning is different. If you use the pattern a :: b :: t
you would need to say compress (b :: t)
, which is a little less elegant and a tiny bit less efficient.
The keyword as
binds a name to all or part of a pattern. Once bound, the name can be used instead of the pattern it represents. In your "compress" function, t
is bound to the pattern b :: _
.
Once t
is bound, it can be used in subsequent expressions, as in the rest of the "compress" function.
as
name binding occurs left-to-right, unlike most languages (excepting C's typedef). Also, ::
appears to have higher precedence than as
.
Therefore, (b :: _ as t)
is equivalent to ((b :: _) as t)
. This can be confusing for those used to right-to-left bindings. Note that a :: (b :: _) as t
will bind the whole pattern a :: b :: _
to t
, due to the precedence mentioned above.
Reference:
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