Just wanted to add two minor points to the discussion. Beforehand let
me say that I *really* like Simon's proposal [despite the various
objections]. Mainly, because it's a small upwards compatible change with
a considerable gain.

Going back to Simon's first `clunky' example.

> Now consider the following definition:
> 
>    clunky env var1 var2 | ok1 && ok2 = val1 + val2
>                       | otherwise  = var1 + var2
>                       where
>                         m1 = lookup env var1
>                         m2 = lookup env var2
>                         ok1 = maybeToBool m1
>                         ok2 = maybeToBool m2
>                         val1 = expectJust m1
>                         val2 = expectJust m2

As a (partial) solution I would suggest to use a simple case expression
involving pairs. [I have not seen this one before, but in my humble
opinion it is the most natural solution in 1.4].

  clunky env var1 var2          =  case (lookup env var1, lookup env var2) of
      (Just val1, Just val2)    -> val1 + val2
      _                         -> ...
 
It scales up nicely when more than three lookups are involved. Of
course, it does not work if `clunky' consists of more than one equation
and the one above is expected to `fail'. [It is debatable, however,
whether it is good programming style to use failing equations. After
all that's what we tell our students:  Use whenever possible disjunct
and exhaustive patterns to separate cases.]

The second point concerns nested guard expressions which I find rather
attractive for the following reason: guards allow to shift nested
conditionals from the rhs to the lhs of an equation. Think of applying
the following transformation:

  lhs                           =  if b1 then e1
                                   else if b2 then e2
                                   ...
                                   else if bn then en
                                   else e
  -->
  lhs | b1                      =  e1
      | b2                      =  e2
      ...
      | bn                      =  en
      | otherwise               =  e

But it may well be the case that one of the ei's also involves an
if-then-else conditonal which I would like to get rid of using the
above transformation: The result are nested guards on the left hand
side. Currently, I must mix guards and top-level if-then-elses which
I'm not particularly fond of.
        Here is a real world ;-) example taken almost verbatim from
ghc'c FiniteMap module which implements Adam's balanced trees.

  mkBalBranch l a r
      | sl + sr < 2                     =  mkBranch l a r
      | sl*ratio < sr                   =  case r of
        Branch _ rl _ rr
          | size rl < 2 * size rr       -> singleL l a r
          | otherwise                   -> doubleL l a r
      | sr*ratio < sl                   =  case l of
        Branch _ ll _ lr 
          | size lr < 2 * size ll       -> singleR l a r
          | otherwise                   -> doubleR l a r
      | otherwise                       =  mkBranch l a r
      where sl                          =  size l
            sr                          =  size r

Note the use of case expression to handle the subcases; for that
purpose irrefutable patterns were once invented. Here we are:

  mkBalBranch l@(~Branch _ rl _ rr) a r@(~Branch _ ll _ lr)

but now we are forced to use an if-then-else for both of the
subcases. Using nested guards we arrive at

  mkBalBranch l@(~Branch _ rl _ rr) a r@(~Branch _ ll _ lr)
      | sl + sr < 2                     =  mkBranch l a r
      | sl*ratio < sr
          | size rl < 2 * size rr       =  singleL l a r
          | otherwise                   =  doubleL l a r
      | sr*ratio < sl
          | size lr < 2 * size ll       =  singleR l a r
          | otherwise                   =  doubleR l a r
      | otherwise                       =  mkBranch l a r
      where sl                          =  size l
            sr                          =  size r

which exposes the different cases quite clearly.

Regards, Ralf



Reply via email to