[Haskell-cafe] Generics & pattern matching

Andres Löh andres at well-typed.com
Thu Dec 6 16:34:55 CET 2012


Hi Joerg.

I must admit that I do not fully understand the big picture, i.e., why
you want to do what you are trying to do. It might be possible to
recommend a better solution using a library such as guarded-rewriting
on Hackage then. I've tried to look up the SO question
(http://stackoverflow.com/questions/13436366/manipulating-arbitrary-tuples),
but it doesn't really make me understand your goal completely either.

In the code you provide, which is taken from one of the answers, the
Bool parameter indeed ensures that the first element of a chain of
products is treated in a different way from the rest. The key to this
behaviour is the line

> rewrite x (a :*: b) = rewrite x a :*: rewrite True b

Here, assuming rewrite is first called with False, we ensure that the
very first component of the nested product will be called with False,
all others with True. Hence all but the first component will end up
being rewritten.

If you'd like to rewrite all but the last, you could achieve this just
by writing

> rewrite x (a :*: b) = rewrite True a :*: rewrite x b

instead. If you want to keep the first and the last component, you
need to propagate more information than a simple Bool. One option is
to create a special-purpose datatype:

> data What = Both | First | Last | None
>   deriving Eq

The type of rewrite becomes:

> rewrite :: What -> f a -> (Rewrite f) a

The idea is that the What argument is initialized to Both, and in
every product case, we split the current value of What to keep track
if we are in the leftmost part of the product (First), the rightmost
part of the product (Last), or elsewhere (None). For this, we define

> splitWhat :: What -> (What, What)
> splitWhat Both  = (First, Last)
> splitWhat First = (First, None)
> splitWhat Last  = (None,  Last)
> splitWhat None  = (None,  None)

The product case of rewrite is now:

> rewrite x (a :*: b) = rewrite y a :*: rewrite z b
>   where (y, z) = splitWhat x

We also need to slightly modify the K1 case of rewrite. We now want to
perform the rewrite if What is anything but None:

> rewrite w (K1 x) | w /= None, Just val <- cast x = K1 val
> rewrite _ _ = K1 "NIL"

Does this help you?

(I'm attaching the full code.)

Cheers,
  Andres

--
Andres Löh, Haskell Consultant
Well-Typed LLP, http://www.well-typed.com
-------------- next part --------------
A non-text attachment was scrubbed...
Name: GRewrite.hs
Type: application/octet-stream
Size: 1592 bytes
Desc: not available
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20121206/57243137/attachment.obj>


More information about the Haskell-Cafe mailing list