14

I'm trying to write a variadic function composition function. Which is basically the (.) except that the second argument function is variadic. This should allow expressions like:

map even . zipWith (+)

or just

map even . zipWith

Currently what I've reached works if I add IncoherentInstances and requires a non-polymorphic instance for the first argument function.

{-# LANGUAGE FlexibleInstances, OverlappingInstances, MultiParamTypeClasses, 
FunctionalDependencies, UndecidableInstances, KindSignatures #-}

class Comp a b c d | c -> d where
    comp :: (a -> b) -> c -> d

instance Comp a b (a :: *) (b :: *) where
    comp f g = f g

instance Comp c d b e => Comp c d (a -> b) (a -> e) where
    comp f g = comp f . g

Any ideas? Is it even possible?

Will Ness
  • 70,110
  • 9
  • 98
  • 181
is7s
  • 3,500
  • 1
  • 20
  • 41
  • 1
    can you explain a bit more what do you mean by "variadic function composition"? maybe add some examples. – max taldykin Mar 11 '12 at 16:44
  • I clarified a little bit in the last edit. Besides that, what's wrong with the two given examples? – is7s Mar 11 '12 at 16:47
  • Oh, sorry. Examples are fine. It was not obvious for me that they do not typecheck. – max taldykin Mar 11 '12 at 16:53
  • 1
    You may want to look at [Concatenative, Row-Polymorphic Programming in Haskell](https://github.com/leonidas/codeblog/blob/master/2012/2012-02-17-concatenative-haskell.md) and [Playing with Factor's Row Polymorphism in Haskell](https://gist.github.com/1847747) since row polymorphism is specifically useful for composing functions of all arities. – rampion Mar 11 '12 at 17:15
  • "Currently what I've reached works if I add IncoherentInstances and requires a non-polymorphic instance for the first argument function." So what is your question, exactly? It might be possible to get around those restrictions, but almost certainly not in plain Haskell 2010. – Dan Burton Mar 11 '12 at 21:54
  • @Dan I want the given examples to work. Which means that I should be able to compose any functions without having to give an instance for the possible types of the second argument function. And hopefully without `IncoherentInstances`. – is7s Mar 11 '12 at 21:58
  • 7
    @is7s, FWIW, anything with "variadic" is not likely to play nice with the rest of the language. It is doable with typeclass hacks, and fun, but I wouldn't recommend it for "real code". – luqui Mar 11 '12 at 22:31

1 Answers1

10

It is possible to type-hack it into working with polymorphic functions:

{-# LANGUAGE FlexibleInstances, MultiParamTypeClasses,
  IncoherentInstances, UndecidableInstances,
  FunctionalDependencies, TypeFamilies,
  NoMonomorphismRestriction #-}


class Comp a b c | a b -> c where
    (...) :: a -> b -> c

instance (a ~ c, r ~ b) => Comp (a -> b) c r where
    f ... g = f g

instance (Comp (a -> b) d r1, r ~ (c -> r1)) => Comp (a -> b) (c -> d) r where
    f ... g = \c -> f ... g c

t1 = map even ... zipWith (+)
t2 = map even ... zipWith
t3 = (+1) ... foldr

But I doubt you can avoid IncoherentInstances

Ed'ka
  • 6,595
  • 29
  • 30