7 ms·
Pattern matching without support for algebraic datatypes really misses the point. What you want is to be able to declare all the shapes of your data, with descr
by jez 9y ago
Pattern matching without support for algebraic datatypes really misses the point. What you want is to be able to declare all the shapes of your data, with descriptive names, and then be able to say definitely "these are the only such shapes."
Pattern matching without exhaustiveness checking and algebraic datatypes is really just a disguise: syntax level changes when the issue is a semantic (i.e. language-level) problem.
- alangpierce 9y agoThe `Payment` example in the post is effectively an implementation of algebraic datatypes. `PaymentPattern` is how the code specifies "these are the only such shapes", and exhaustiveness is checked because the typechecker won't let you provide a `PaymentPattern` that omits any cases. It's certainly not as flexible as pattern matching like you'd get in a serious functional language, but I think it handles the use case "condition over cases of an algebraic type" just fine.
- z1mm32m4n 9y ago> The `Payment` example in the post is effectively an implementation of algebraic datatypes. Algebraic data types are what we call "initial": they're characterized by how they're built up structurally. The 'PaymentMatcher' example, while using the terms "matcher" and "pattern" in the variable names, is actually closer to a "final" solution, since they're characterized by how they behave. This is a bit abstract, but to put it simply, the key difference between what you and I are talking about is the same difference between algebraic datatypes and type classes. Algebraic datatypes are built up with constructors, and then exist structurally. On the other hand, type classes are more ephemeral. When declaring a type class, we say "these N methods are the ways you can 'poke' and 'prod' me to get a response," that is, it's the behavior of the type class that's most important. So in fact, it's not that algebraic datatypes are more flexible than type classes or vice versa, but rather that they're duals of each other; they codify similar concepts, but approach the problem from two different sides. I find this sort of stuff fascinating! Some of my favorite articles dealing with these sorts of nuances: - Typed Tagless Final Interpretters[1] - Practical Foundations for Programming Languages, Chapter 15 "Inductive and Coinductive Types"[2] [1]: http://okmij.org/ftp/tagless-final/course/lecture.pdf http://okmij.org/ftp/tagless-final/course/lecture.pdf [2]: http://www.cs.cmu.edu/~rwh/pfpl.html http://www.cs.cmu.edu/~rwh/pfpl.html
- masklinn 9y ago> Pattern matching without support for algebraic datatypes really misses the point. That's really not true, Erlang has neither static types nor sum types (which I expect is what you mean by ADT rather than including product types) yet several of its construct (not least of which "assignment") make great use of pattern matching. Pattern matching is one of the most important tools in Erlang's toolbox. > What you want is to be able to declare all the shapes of your data, with descriptive names, and then be able to say definitely "these are the only such shapes." > Pattern matching without exhaustiveness checking and algebraic datatypes is really just a disguise Also not necessarily true, closed sum types are probably the best default but OCaml's polymorphic and extensible variants are genuinely great tools.
- platz 9y ago'the point' that OP cares about is exhaustiveness. one can disagree of course; but without exhaustiveness what you really have is destructuring (this is not what OP cares about)- erlang is a fine example
- masklinn 9y ago> without exhaustiveness what you really have is destructuring- erlang is a fine example That's completely nonsensical. Erlang does not have exhaustiveness yet is not limited to destructuring. In fact, mere destructuring is probably the least common of pattern matching's uses in Erlang, much more common are asserting, filtering and dispatching (all of which may make further use of destructuring internally but destructuring is a sub-component of the match rather than the pricipal).
- tarsinge 9y agoNot just destructuring, see https://elixir-lang.org/getting-started/pattern-matching.html https://elixir-lang.org/getting-started/pattern-matching.htm... for example
- rbehrends 9y agoWithout exhaustiveness checking, you still get a more advanced typecase-like control flow construct, not just destructuring. In practice (and non-trivial code), exhaustiveness checking plays much less of a role, especially if you already have an object-oriented language. In basic OO languages, you get exhaustiveness through abstract methods AND get the ability to add subtypes to an existing sum type. One advantage of pattern matching is that it's easier to add actions (instead of subtypes), a.k.a. the expression problem. But that's a modularity issue, has nothing to do with exhaustiveness, and can also go the other way (as pattern matching makes it hard to add new variants to an ADT in a modular fashion). Another advantage is that pattern matching can be a poor person's tree parser, but for that, exhaustiveness doesn't buy you much, because ADT patterns also typically allow for patterns that aren't allowed by the underlying tree grammar, so you'll have an `_ -> assert false` fallback case often enough.
- dragonwriter 9y ago> Pattern matching without support for algebraic datatypes really misses the point. The idea that pattern matching has only one point misses the point. > What you want is to be able to declare all the shapes of your data, with descriptive names, and then be able to say definitely "these are the only such shapes." While that is useful, it's not always the most important thing I want with pattern matching, it's usually a nice to have. If I can match on the shapes I can meaningfully handle in a particular point and use a default case with appropriate behavior (which may be to report an error condition) for any others, that's often enough.
- platz 9y agoThe problem is that blog posts often start out with the phrase "pattern matching like haskell or scala" and then describe a mechanism that is not like those—it misrepresents and conflates what those languages provide.
- rbehrends 9y agoThis would be news for Prolog programmers, I think (or any other logic programming language). Consider also tree parsers or languages with predicate dispatch (both of which are, functionality-wise, a strict superset of pattern matching).
- hoodunit 9y agoYou can get exhaustiveness checking in some cases in TS by adding a default statement to a switch and assigning the value to type 'never'. This is a bit cumbersome, of course, and the fact that it's opt in partly defeats the purpose. You typically want to check exhaustivity to get more safety, but there the safety only comes if you add it in manually so everywhere you forget you lose safety.