Hacker News new | past | comments | ask | show | jobs | submit login

How does F#'s pattern matching compare to Erlang's?



They're similar in what they are used for, but they come from different traditions and so have some differences.

F# patterns come from ML, with active patterns added on top. Erlang patterns come from Prolog, with unification removed.

A quick example, in Erlang you can write:

   1> (X = {1 = A, [2, 3]}) = {1, [2, 3]}.
   {1,[2,3]}
As well as:

   1> ({A = 1, [2, 3]} = X) = {1, [2, 3]}.
   {1,[2,3]}
That is, the `=` is actually a pattern matching operator and the order of its two operands doesn't matter (well, not really, not everywhere - that's where the "removed unification" comes from - but close enough). That's because in Prolog the `=` operator denotes actual equivalence, not an assignment, and Erlang inherited that.

In F# and OCaml this is done with a special operator, `as`, and it cares about the order of its operands very much. You can do this:

   > let (1 as a, [2; 3]) as x = (1, [2; 3]);;
   val x : int * int list = (1, [2; 3])
   val a : int = 1  
but

   > let (a as 1, ...etc
obviously won't work.

All in all, both mechanisms work quite well and you can translate between them easily, but they are not 100% equivalent. Erlang has much simpler syntax (it's basically just `=`) while F# adds `as`, `&` and other constructs. In Erlang, once a name is matched with an expression, it is equivalent to that expression and stays that way forever. In OCaml, you can readily reassign matched names. That also makes Erlang pattern matching act like an assert and (identity) comparison in some situations, which are both different things in F#.

So, the use-cases are very similar, but the concepts underlying the mechanisms differ which in turn makes some details of the mechanisms differ too. Both are a joy to work with, to be sure, compared to the "applied ifology" or the dreaded `switch` statement, though :)


Yep, Erlang's use of = operator's pattern matching / assignment allows for some very elegant solutions, in addition to function guards, deconstruction, and other use-cases.

It basically uses pattern matching as a fundamental/primitive part of the language design, rather than some useful add-on or tertiary feature.


The flipside is that in Erlang often need repetitive code like so:

      case X of
         {expense, N} -> Total - N;
         {invoice, N} -> Total - N;
         {loss, N}    -> Total - N;
         {credit, N}  -> Total + N
       end
         
whereas in ocaml (and F#, modulo details) you could just do something like:

      match x with 
          | (`expense, n) | (`invoice, n) | (`loss, n) -> total - n
          | (`credit, n) -> total + n;;
The examples are unidiomatic and artificial and you can sometimes ameliorate it with guards, but it's a frequent (minor) annoyance.


Close enough?

  case X of
    {Cat, N} when Cat == expense; Cat == invoice; Cat == loss  -> Total - N;
    {credit, N}  -> Total + N
  end


patrec said that

> you can sometimes ameliorate it with guards

which is exactly what you did, so I don't think you're disagreeing here :)


That's a neat pattern in F#, I like it!

In Erlang's case (pun intended!) I'd probably go for a function though:

    total({expense, N}, Total) -> Total - N;
    total({invoice, N}, Total) -> Total - N;
    total({loss, N},    Total) -> Total - N;
    total({credit, N},  Total) -> Total + N.


That still repeats the `Total - N` 3 times, though. As patrec said, it's possible to work around this with guards in this specific case, but in general this kind of duplication is indeed common in Erlang code. You can avoid it many cases by correctly factoring the code, but it's not always possible and then it's a bit irritating. Not too much, though. It's basically the difference between fall-through and non-fall-through `switch` statement: OCaml/F# allow fall-through (as an option, not by default, thankfully), Erlang/Elixir/LFE don't.


Thanks for the detailed answer.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: