Tuesday, December 13, 2011

[dgokhmib] Case statements thwart point-free

Case expressions in Haskell force binding values to names in two places, suggesting future improvements to syntax to encourage point-free programming style.

The first is the expression being examined.  We would like to do this: f . \e -> case e of { ... } . g but without having to name it e.  Here is a simple addition to syntax to fix this: f . LAMBDACASE { ... } . g .  It might make sense to deprecate plain case and always use LAMBDACASE.

The second is capturing values in pattern matching.  Haskell lacks a syntax to take the value from a pattern binding and pass it along to a function without ever having to assign the value to a bound variable name.  We want f $ g $ case e of { Foo x -> x } without ever having to temporarily name x.  Here is one possible weird syntax: FUNCTIONCASE e of { Foo \(f . g) }.   If the constructor has many fields, then the other captured variables are available, for example to a curried function : FUNCTIONCASE e of { Foo x _ _ \(f x y) _ _ y }

This effect is somewhat possible with named fields (record syntax).

We probably want LAMBDAFUNCTIONCASE to combine these.

3 comments :

Anonymous said...

The whole point of point free is less syntax. It is better to use folds instead of special syntax.
For example,
instead of
case x of
Nothing -> 0
Just x -> x
one could do
maybe 0 id
which is much cleaner.
P.S.
Perhaps folds should be generated by the compiler automically when a datatype is defined. As well appropriate loop fusion laws could be automatically defined as well.
Or perhaps recursion should be restricted to a special datatype Nu :: (* -> *) -> * and there should just be one primitive definition of fold.
fold :: Nu f -> (f a -> a) -> a .

Anonymous said...

Translating Haskell functions into pointfree form requires support functions. For instance, it's impossible to transform a function that uses a bound variable more than once, like "f x = (g x) (h x)", without a helper function like "j f x = f x x".

Likewise, any case statement of a sum type can be transformed into pointfree form with use of a destructor function like maybe.

data Q a = C X | D Y | E Z a

destructQ :: (X -> b) -> (Y -> b) -> (Z -> a -> B) -> Q a -> b
destructQ fC fD fE q = case Q of
C x -> fC x
D y -> fD y
E z a -> fE z a

Cale Gibbard said...

It has been suggested that like with other places in the Haskell syntax, one should be allowed to form a section of case by eliding the scrutinee:

case of { ... }

would then translate into

\fresh -> case fresh of { ... }

where fresh is a fresh choice of variable.