
On Thu, Jul 26, 2007 at 11:28:03AM -0400, Dan Licata wrote:
I think what you're describing is equivalent to making the "implicit view function" syntax so terse that you don't write anything at all. So the pattern 'p' is always (view -> p).
Thanks, I wouldn't have thought of such a simple explanation myself :)
This seems like a pretty invasive change:
I don't think the version with the functional dependency works (unless you adopt some form of scoped type class instances, as you suggest below), because then if you want to use a datatype as a view, you can no longer pattern match on the datatype itself at all! Even with some form of scoping, you can't decompose the view datatype as itself and as a view in the same scope.
Right, you can't pattern match on a type that is used as a view. But from what I've seen in library code, that usually doesn't happen - nobody matches ViewL except with viewl in the scrutinee, etc. You could create a proxy type (at some cost in ugliness) in the cases where you want to use the same structure for a concrete type and a view.
The non-functional type class will make everything very polymorphic (e.g., where we used to infer a type based on the datatype constructors that occurred, we will now say that it's anything that can be viewed as that datatype).
That's exactly the typing problem that I ... no wait I didn't actually mention it. :)
So, this syntax affects a lot of code, existing or otherwise, that doesn't use view patterns, which is something we're trying to avoid.
Eh? I *think* the typing rules are the same for the no-view case. If the auto-deriving hack isn't implemented, you only need a deriving(View), otherwise there should be no change at all... Stefan
It's possible to go even simpler, and implement views via a simple desugaring without altering the typechecking kernel at all.
(for simplicity of exposition, assume pattern matches have already been compiled to flat cases using Johnsson's algorithm; in particular the patterns mentioned consist of exactly one constructor, not zero)
case scrut of pat -> a _ -> b
==>
realcase (Prelude.view scrut) of pat -> a _ -> b
Where in the Prelude (or the current type environment, if -fno-implicit-prelude) we have:
class View a c | c -> a where view :: a -> c
and we provide a deriving-form for View which generates View Foo Foo where view = id.
Or, a rule which does that automatically if no explicit instance of View _ Foo is in the current module.
Or, remove the fundep and add an instance View a a where view = id to the Prelude.
Option 3 makes definitions more polymorphic. Options 1 and 2 keep the same level of polymorphism as before; 1 is simpler but breaks old code.
Note that none of these options supports the value input feature; we need new syntax to support non-binding identifiers in patterns!
Stefan