data Suit = Spades
| Hearts
| Clubs
| Diamonds deriving (Show, Eq, Bounded, Enum)
this creates a type that acts exactly like an enum. With the added benefit of having a well-defined string representation and maxBound/minBound constants for free.ADTs and enums are meant to prevent this.
Smalltalk isn't about preventing things, it's about enabling them.
Anyone who's used the object-oriented part of OCaml can tell you that inheritance can mix with Hindley-Milner awkwardly... but I'm not sure that really means algebraic types and pattern matching couldn't be integrated into Java, Python, or whatever somehow. For all I know, maybe it's already on the way into C++...
Ambiguous, because in the:
# y = 5
#
match x with:
1: "my string"
2|3: print "2,3"
y: print y
there is a problem. Because, really, in case of 'y' you want to be able to do both: bind variables; use already defined variables. And there is no way you can do both with clean and concise syntax. On the other hand, there is already a way to achieve the same results with if,elif,else. That's why (sadly) pattern matching is not there.Every language solves that with a desambiguation rule. In haskell, the first matching line runs. It's no worse than the way C, Java, and family solve the if-else ambiguity, for example.
|y -> y + x
If y was defined in the outside scope, the case scope just shadows it. y = 5
match x with:
1: print '1'
y: print '5'
he will think it is equivalent to: y = 5
if x == 1: print '1'
elif x == y: print '5'
And that would not be true.let y = 5 in
match x with 1 -> print "my string" | 2 | 3 -> print "2,3" | z when z = y -> print y
matching a value of variable:
|z when z = y -> print y
free matching with a bind: |y -> print y
matching several values: |2|3 -> print "2 or 3"
matching tuples: |2,3 -> print "tuple 2,3"
Now, if I'm trying to come up with such syntax for Python, I see immediate problems. For example, lets consider following syntax for matching several values: match x with:
1: print "my string"
2,3: print "2,3"
Would it be equivalent to matching a tuple (2,3) or matching one of the values 2 or 3? Ambiguous. So you need some other syntax. Let's try a few variations: match x with:
1: print "my string"
2:3: print "2 or 3" # plain ugly
2|3: print "2 or 3" # interferes with '|' op
in (2,3): print "2 or 3" # too complicated
x in (2,3): print "2 or 3" # elif was simpler
Or consider: match x with:
1: print "my string"
y: print y
Would that be matching a value of variable (|z when z = y -> print y), or free matching with a bind (|y -> print y)?Having experimented with that a bit, I have a feeling, that it's just impossible to make up 'match' syntax for Python that would fit into the language. And I think that's why it is not there. And why we don't even want match syntax there. Now, of course I'd be happy to change my opinion, if somebody would rise up to the challenge and come up with some syntax that fits.
ML (Ocaml, I should say, because that's my experience) is like a functional C. As a production language, I'd recommend it highly. It has excellent garbage collection. It generates blazingly fast native code.
I can't speak either way about Haskell's use in production. I'm sure that many people have made it work. I just don't know how hard it is in practice.
Haskell is lazy, for one, which makes it hard to reason about performance. You can have production memory leaks that are a bitch to debug. It also has a much more powerful, but also more complex type system. Explicit functors (Ocaml) are replaced by implicit type classes, which make the language more attractive (I'll grant that) but also make it easier to hang yourself by the monads.
Haskell's still a great language, and there are a million things that recommend it. However, I don't see it as occupying the same space as the ML family. The main similarity is that both use Hindley-Milner type inference, but there are a lot of differences, too.
Finally, Haskell is pure (except in the IO Monad, and a couple others) while Ocaml's not. You have stateful arrays and ref cells in Ocaml, and use them all the time when you're writing high-performance production code. In Haskell, any IO is to be done "in the IO monad" (which means, "in the context of evaluating an IO a", the latter being a thunk that does IO and returns an a.)
To be precise, it's type _inference_ of Damas-Hindley-Milner + Typeclasses that poses the most gotchas. (Plain vanilla DHM is just ML. You can hack Haskell without class, but you can't get the class out of Haskell.)
Experience with Prolog helps, since a form of logical deduction, generally speaking, is what's happening behind the scenes. You could think of the compiler as applying AI to figure out the types. This kind of AI is magic when it works and baffling when it barfs.
One way out is to skip the AI entirely and annotate all the types by hand. Now the compiler only has to check types, not infer them. When it stumbles over imperfect code, the error messages become a lot more decipherable.