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.


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.
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.