Albert Y. C. Lai trebla at vex.net
Fri Aug 17 21:59:26 EDT 2007

```Dan Weston wrote:
> I hate to be a party pooper, but isn't this just:
>
>  > f = foldr (\a z -> (a:snd z,fst z)) ([],[])
>
> This takes less time to grok and takes no longer to run.

For each type with exported constructors, one can always write
deconstructors for it, if not already found in libraries. One may then
argue that ~ is never necessary. Given

f ( ~(Left (z0,_)) : Right ~(Just z1) : xs ) = (z0, z1, xs)

you can always hand-compile to

f (x0 : Right y1 : xs) = (fst (getLeft x0), fromJust y1, xs)

But ~ is desirable:

0. Which version is easier to understand?

That is a bit subjective, but I think it comes down to this. (As do all
debates over whether concise notation is readable, really.) To a kid who
has not learned the word "arctan", I have to say, "draw this
right-angled triangle, with this side being length 3, that side being
length 4, now measure this angle, that is what I mean by arctan(3/4)" -
you know, all the details, step by step, hand in hand. To a learned
adult, I can just say, "arctan". In fact, if I spelt out the details to
the adult, step by step, hand in hand, he/she would think I'm
condescending or counterproductive.

Specifically in the case of ~, it makes transparent the structure of the
data to be expected: By just reading one spot, you see it wants a list
of two or more items, the first item is a Left, in which there is a
tuple, the second item is a Right, in which there is a Just.

That same information is torned apart without ~: part of the information
is on the left, and the rest is hidden on the right to be recovered from
This is because it is more low-level. The "what" is encoded beneath the
"how". You follow the code execution and then you reverse-engineer its
purpose. It is quite attractive when you have no notation to denote the
purpose. It is a poor choice when you have a notation to denote the
purpose: "what" data parts are wanted, and "when" they are wanted,
without reading a single function call, the "how".

1. Which version is easier to change strictness?

Strictness and non-strictness are tricky to get right for performance or
even mere feasibility. An important programming activity is
investigating various levels of strictness. It is imperative to be able
to change strictness efficiently.

the ! strictness annotation understands this one too. By just toggling
~'s you toggle non-strictness. It's that easy to change.

Here is the function again. I'm going to change its strictness.

f ( ~(Left (z0,_)) : Right ~(Just z1) : xs ) = (z0, z1, xs)

I now want the second cons to be later, the Left to be earlier (at the
same time as the first cons), the tuple to be later, the Right to be
later (even later than the second cons), and the Just to be earlier (at
the same time as the Right). I can do that by just toggling ~'s:

f ( Left ~(z0,_) : ~(~(Right (Just z1)) : xs) ) = (z0, z1, xs)

Without ~, much more change is necessary. Here is the non-~ code before
change again:

f (x0 : Right y1 : xs) = (fst (getLeft x0), fromJust y1, xs)

The change is:

f (Left y0 : xs) = (fst y0, fromJust (getRight (head xs)), tail xs)

Both sides have to be changed. On the left, the data structure has to be
changed. On the right, the function call structure has to be changed.
You have to remove a constructor on the left and add a deconstructor on
the right, or add a constructor on the left and remove a deconstructor
on the right. This is a dream come true for IDE marketeers. This code
manipulation is too annoying to be done by hand on a daily basis, yet
mechanical enough to be done by software easily. A marketeer can sell an
IDE plugin for this and garner much money and gratitude from
unsuspecting programmers, capitalizing on the fact that some languages
do not provide an annotation to trivialize this whole business, and in
those that do, some programmers refuse to use it.

```