[Haskell-cafe] Client-extensible heterogeneous types (Duck-typed variadic functions?)

Max Bolingbroke batterseapower at hotmail.com
Thu Oct 14 03:56:07 EDT 2010

On 14 October 2010 08:34, Jacek Generowicz <jacek.generowicz at cern.ch> wrote:
> Those other data might be the functions' arguments, or they might be other
> functions with which they are to be combined, or both.

You can represent these as existential packages. However, as Oleg
shows you can always use skolemisation to eliminate the existential:

This trick is basically what Brandon and Evan pointed out earlier when
they suggested you replace the list :: [exists b. (b -> a, b)] with a
list :: [a].

> Here's an example where lazy evaluation isn't enough:
> def memoize(fn):
>    cache = {}
>    def memoized_fn(*args):
>        if args not in cache:
>            cache[args] = fn(*args)
>        return cache[args]
>    return memoized_fn
> You memoize a function once, but it will be given different arguments, many
> times, at a later time.

I'm not sure why you would use existentials for this. Isn't the type
of memoized_fn just :: Ord a => (a -> b) -> a -> b?

This doesn't deal with argument *lists* so you may have to
curry/uncurry to get functions of a different arity to go through, but
that is IMHO a reasonable requirement for Haskell, where
multi-argument functions do not have special status.

(In the absence of side effects, I can't see an obvious way to
implement it without some way to enumerate the domain "a" though.
Conal Elliot uses type classes to solve this issue, see
http://hackage.haskell.org/package/MemoTrie, where memo :: HasTrie t
=> (t -> a) -> t -> a).

> will do. So please allow me to store (fnA1, fnA2) and (fnB1, fnB2) in the
> same place. The program can tell that it can combine them with (.) because
> the type of

But if the only operation you ever do on this pair is (.), you may as
well skolemise and just store (fnA1 . fnA2) directly. What is the
advantage of doing otherwise?


More information about the Haskell-Cafe mailing list