[Haskell-cafe] Polyvariadic functions operating with a monoid

Luke Palmer lrpalmer at gmail.com
Sun Oct 3 15:26:24 EDT 2010


On Sun, Oct 3, 2010 at 1:24 AM, Kevin Jardine <kevinjardine at gmail.com> wrote:
> I had a situation where I had some related types that all had toString
> functions.
>
> Of course in Haskell, lists all have to be composed of values of
> exactly the same type, so instead of passing around lists of values
> with these related types, I created a polyvariadic function
> polyToString so that I could write:
>
> (polyToString value1 value2 value3 ... valueN)
>
> which would then become a list of strings:
>
> [toString value1, toString value2, ... , toString valueN]

First of all, you are not using the monoidal structure of String at
all.  This trick ought to work for any type whatsoever -- you're just
throwing them in a list.

Other than a few brackets, commas, and a repeated identifier (which
you can let-bind to shorten), what benefit is it giving you?  I
strongly recommend against polyvariadic functions.  While you get a
little bit of notational convenience, you lose composability.  There
are pains when you try to write a function that takes a polyvariadic
function as an argument, or when you try to feed the function values
from a list, etc.  The mechanisms to create polyvariadic functions are
brittle and hacky (eg. you cannot have a polymorphic return type, as
you want in this case).

Since all your values are known statically, I would recommend biting
the bullet and doing it the way you were doing it.

    [ s value1, s value2, s value3, ... ]
       where
       s x = toString x

(I had to eta expand s so that I didn't hit the monomorphism restriction)

When you want to be passing around "heterogeneous lists", it usually
works to convert them before you put them in the list, like you were
doing.

> I finally figured out how to do this, but it was a bit harder to
> figure this out than I expected, and I was wondering if it might be
> possible to create a small utility library to help other developers do
> this.
>
> It seems to me that in the general case, we would be dealing with a
> Monoid rather than a list of strings. We could have a toMonoid
> function and then return
>
> polyToMonoid value1 value2 ... valueN =
>
> (toMonoid value1) `mappend` (toMonoid value2) 'mappend' ... (toMonoid
> valueN)
>
> So anyone who wanted to convert a bunch of values of different types
> to a Monoid  could easily pass them around using polyToMonoid so long
> as they defined the appropriate toMonoid function.
>
> Basically, a generalised list.
>
> So I tried writing the following code but GHC said it had undecidable
> instances.
>
> Has this ever been done successfully?
>
> class Monoidable a where
>    toMonoid :: Monoid r => a -> r
>
> polyToMonoid :: (Monoidable a, Monoid r) => a -> r
> polyToMonoid k = polyToMonoid' k mempty
>
> class PolyVariadic p where
>    polyToMonoid' :: (Monoidable a, Monoid r) => a -> r -> p
>
> instance Monoid r => PolyVariadic r where
>    polyToMonoid' k ss = (toMonoid k) `mappend` ss
>
> instance (Monoidable a, Monoid r) => PolyVariadic (a -> r) where
>    polyToMonoid' k ss = (\a -> polyToMonoid' k (toMonoid a) `mappend`
> ss)
>
> _______________________________________________
> Haskell-Cafe mailing list
> Haskell-Cafe at haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>


More information about the Haskell-Cafe mailing list