Re: [Haskell-cafe] Polyvariadic functions operating with a monoid

2010-10-03 Thread Luke Palmer
On Sun, Oct 3, 2010 at 1:26 PM, Luke Palmer  wrote:
> On Sun, Oct 3, 2010 at 1:24 AM, Kevin Jardine  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@haskell.org
>> http://www.haskell.org/mailman/listinfo/haskell-cafe
>>
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe


Re: [Haskell-cafe] Polyvariadic functions operating with a monoid

2010-10-03 Thread Luke Palmer
On Sun, Oct 3, 2010 at 1:24 AM, Kevin Jardine  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@haskell.org
> http://www.haskell.org/mailman/listinfo/haskell-cafe
>
___
Haskell-Cafe mailing list
Haskell-Cafe@haskell.org
http://www.haskell.org/mailman/listinfo/haskell-cafe