Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Pattern-matching is not sugar over "case".

Pattern-matching means that the branching primitive not only dispatches to different code based on an input tag, but also that it places different values of different types in scope according to the branch.

Most languages only branch on booleans, without gaining any type information at all. This is actually a big problem and relates to the nullability problem, explained at: http://existentialtype.wordpress.com/2011/03/15/boolean-blin...

For example, in C:

  switch(ptr) {
  case NULL: ... handle null case ...
  default: ... use ptr as if it weren't NULL ...
  }
This is unsafe -- because nothing prevents you from using ptr in the "NULL" case, and the compiler does not give you anything in the non-NULL case.

In Haskell:

  case ptr of
    Nothing -> ... can't use ptr as a value here,
                   it's wrapped with Maybe ...
    Just x -> ... pattern-matching gave us "x" of
                  the correct type.
                  We can now safely use it.


As Tyr42 has so astutely observed, I have meant that pattern matches in function declarations, let-bindings and list comprehensions are desugared into the case expression. Also, it would be kind of pointless to compare C switch and Haskell case. Especially, in your example Haskell, probably, 'wins' because primarilt because a more powerful type system and algebraic data-types (and absence of pointers, hehe). That said, it's not like you can't emulate the pattern matching (with placing nested values/subtrees in scope): https://gist.github.com/2832755 (it's in JavaScript, because I felt like it -- but I'm pretty sure you can devise something similar in C). Of course, it's plain ugly and doesn't carry any nice static guarantees that the Haskell type-system will give you (like warning about incomplete patterns)... but, hey, it works. Anyway, the point of my comment was that pattern-matching is hardly a feature characterizing and exclusive to Haskell (ML/OCaml/F#, Coq, Scheme have it, probably other functional languages too). Although, it's still the one I enjoy every day :)


In a dynamically typed language, whether you do pattern matching or boolean-blind branching doesn't matter that much. You'll catch any error at runtime anyway.

In the presence of static typing, "emulating" pattern matching defeats the purpose, because the purpose of pattern matching is removing boolean blindness. With the "emulated" code you still get runtime-failing boolean-blind code.

By the way, pattern-matching is indeed very much related to sum types (part of "Algebraic data types"), which C lacks. To have pattern matching in a statically typed language, you would need to have sum types as well.


Well, he could be talking about

    reverse [] = []
    reverse (x:xs) = reverse xs ++ [x]
being sugar for

    reverse list = case list of
               []     -> []
               (x:xs) -> reverse xs ++ [x]
Since in that case, pattern matching on arguments is really just sugar for a case statement.


case is pattern-matching, though.

He said pattern-matching was sugar for "case/switch construct present in many, many languages". That implies pattern-matching adds only syntax to the game, and that it doesn't add any useful things beyond the "switch" you find in C or Java, for example.


I was looking for a forgiving interpretation of his statement. It's better to assume someone is right, and a little unclear, then just outright wrong.


Sure, and I'd do the same if he said it was just sugar over "case", but he explicitly said "case/switch found in many languages", which makes it pretty definite IMO.




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

Search: