
http://hackage.haskell.org/trac/haskell-prime/wiki/ViewPatterns
I'm thinking of implementing it in GHC, so I'd be interested in feedback of the form - how desirable is it to have a feature of this general form? - can this particular proposal be improved?
IMHO, getting a handle on the ADT vs pattern matching issues is overdue, so thanks for raising this again. a few first comments: 1 I am a bit concerned about the use of non-linear patterns in your examples. There are good arguments for non-linear patterns, and Haskellers have made good arguments against non-linear patterns. But you seem to suggest allowing non-linear patterns in some cases (related to view patterns), but not in others (general patterns). That is likely to be confusing. 2 view patterns nicely separate expressions in patterns from pattern variables. But I didn't realize at first that view patterns can be used nested inside other patterns. Yet this variable binding during nested matching is the essential contribution, and the only reason why the extra syntactic sugar is justified. Perhaps this point could be repeated and emphasized in "The proposal more formally", for people like me?-) 3 what you call first class abstractions are not entirely orthogonal to view patterns. taking Tullsen's and my own proposal as examples: - the way patterns and alternatives are handled needs to fit together. that doesn't seem to be a problem since your and our proposals agree on using what I call a monadic data parsing framework (using a MonadPlus such as Maybe to handle pattern match failure and alternatives) - all three proposals have discussed how to handle patterns as well. For Tullsen, that is central to his proposal, for me, it was only one of the more advanced examples because I wanted to focus on match alternatives first. Tullsen first builds his pattern combinators, then outlines a point-free style that avoids the need for pattern variables althogether but does not seem to scale well, then suggests syntactic sugar for translating patterns with variables into applications of his combinators. So that last part is closely related to, if different from, your proposal. In my example, I build up patterns from de-constructors (which use tests and selectors), so that a cons pattern takes a head pattern and a tail pattern as parameters and applies them to the head and tail if it is applied to a non-empty list. To handle variables, I use an old trick from the early functional logic languages, namely that logic variables can be passed unbound, then bound to values later, just what we need for pattern variables. Since Haskell doesn't have logic variables, I have to simulate them, which is the only awkward bit of the example: http://www.haskell.org/pipermail/haskell-prime/2006-November/001915.html as long as Haskell doesn't support logic variables, some syntactic sugar for variables in nested patterns, such as Tullsen's or your's, is probably inevitable. 4 whether to use view patterns inside ordinary patterns, or whether to build up patterns from abstract de-constructors (just as expressions are built from abstract constructors) may seem only a question of style. but if your aim is to encourage people to transition from exporting concrete data types to exporting abstract types only, the latter approach seems more consistent to me. In my example, a cons de-constructor would be as simple as -- the cons view of array lists is a higher-order pattern that takes -- patterns for the head and tail components, and applies them after -- checking whether the list parameter is a non-empty list consAP h t l = do { Match $ guard $ not (isNilA l); h (headA l); t (tailA l) } but that relies on the scoping of (simulated) logic variables, and it does not translate directly to your view patterns, as the h and t pattern parameters would have their own scope for their pattern variables. It would be instructive to have something equivalent to pattern constructors/abstract deconstructors for view patterns, if only to see whether view patterns can support a fully abstract style of nested matches easily. I am not entirely sure they do, but here is a first attempt: -- abstract list deconstructors / list pattern constructors -- (consP takes h/t sub-patterns as parameters) consP h t l = do { guard $ not (null l); hr <- h (head l); tr <- t (tail l); return (hr,tr) } nilP l = do { guard $ null l; return () } -- wildcard and variable patterns wildP l = return () varP = return -- extract the head of the tail of the parameter list, if that list has two elements f (consP wildP (consP varP nilP) -> (_,(x,_))) = x It seems a bit awkward to have to specify the structure of the parameter twice, once to build up the pattern, then again to match sub-expressions to variables. but would this work in principle at least? 5 possible extension 1 smells of superfluous complexity. There is almost no gain compared to using tuples, but there's a lot to pay in added types and rules. 6 possible extension 2 seems a non-starter if we want compositional abstract patterns, and I certainly do want them. Imagine the example in (4) with explicit Maybe. Being able to have compositional abstract patterns would be the make-or-break criterion for me. Without them, new syntactic sugar wouldn't be justified, with them, their precise form is a matter of convenience. Claus