[Haskell-cafe] Polyvariadic functions operating with a monoid

Luke Palmer lrpalmer at gmail.com
Sun Oct 3 15:30:39 EDT 2010


On Sun, Oct 3, 2010 at 1:26 PM, Luke Palmer <lrpalmer at gmail.com> wrote:
> 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.

Oops, sorry for not reading your message more closely.  You were
indeed talking about the monoidal structure of list.  So... nevermind
about this comment.  :-P

> 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