AW: slide: useful function?

Frank Atanassow franka@cs.uu.nl
Mon, 2 Dec 2002 17:20:21 +0100


John Hughes wrote (on 02-12-02 10:27 +0100):
> > On Mon, 2 Dec 2002, Andrew J Bromage wrote:
> >
> > > ... If you mention a term like "design patterns",
> >
> > well I love design patterns, it's just that in Haskell-land
> > they are called higher-order functions, or polymorphic functions, etc.
> >
> > -- Johannes Waldmann ---- http://www.informatik.uni-leipzig.de/~joe/ --
> 
> Or maybe more general notions, such as
> 
>    "define a recursive datatype together with a catamorphism combinator"
> 
> or even
> 
>    "embed a domain-specific language via combinators over an ADT"
> 
> There are patterns of that sort in our programs, which we would probably
> rather call design techniques, which aren't so easily captured by a
> higher-order function definition.

And yet these are two examples which might reasonably be adopted, like HOFs,
as language features:

  1) most recursive datatypes, including nested datatypes, determine a unique
     catamorphism, so we could generate it for the user automatically, or
     provide a fold-expression analagous to the case-expression, as in
     Charity;

  2) similarly, many polymorphic datatypes, together with a specification of a
     notion of variable or environment, determine a substitution monad for an
     embedded DSL, so we could generate the map, unit, join, bind and
     substitution functions automatically from the spec, and I imagine one
     could provide a sort of quasiquotation syntax for specifying terms of the
     DSL (which is, though, not so far from do-syntax as we have it now).

There is a strong trend in declarative languages, I think, where "design
patterns" evolve into more bullet-proof language features, precisely because
design techniques in declarative languages are susceptible to formal
analysis.

For example, I think this is how algebraic datatype declarations (and perhaps
arguably modules) evolved in ML. In a short discussion at the end of
Tatsuya Hagino's thesis ("A Categorical Programming Language"), he describes
how abstract datatypes were adopted by SML as a primitive part of the
declaration syntax. In the original ML developed for LCF, datatypes were
declared like this:

  absrectype btree = int + (btree # btree)
    with leaf n = absbtree(inl n)
    and node(t1,t2) = absbtree(inr(t1,t2))
    and isleaf t = isl(repbtree t)
    and leafvalue t = outl(repbtree t)
    and left t = fst(outr(repbtree t))
    and right t = snd(outr(repbtree t));;

The modern equivalent is:

  data Btree = Leaf Int | Node (Btree, Btree)

Imagine (or, "recall", if you are old enough :) having to declare all those
introduction and elimination primitives for every datatype! Maybe in a few
years we will be looking back and saying the same about catamorphisms and
DSLs...

-- 
Frank