16

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?

Gilles 'SO- stop being evil'
  • 104,111
  • 38
  • 209
  • 254
Vincent Tjeng
  • 693
  • 8
  • 25

2 Answers2

19

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.

Jeffrey Scofield
  • 65,646
  • 2
  • 72
  • 108
  • Could you explain why it is less efficient? – Michael Sep 04 '19 at 11:27
  • 3
    The form with `as` uses the existing tail of the list. The form without `as` conses up a new list from `b` and `t`. So the latter takes a tiny bit of extra time and consumes a small amount of extra space. – Jeffrey Scofield Sep 04 '19 at 16:15
13

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:

earthfront
  • 141
  • 1
  • 3