Here's a pretty simple approach using type families that works monomorphically in the numeric type (e.g., specialized to Int). We'll need a few extensions:
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE TypeFamilies #-}
The function f will be defined in a type class:
class VarArgs r s where
type F r s
f :: r -> s -> F r s
and we'll handle the following cases. If the type of the first function is of form a :: Int -> r, we'll use the following instance to gobble an argument x and feed it to a:
instance VarArgs r s => VarArgs (Int -> r) s where
type F (Int -> r) s = Int -> F r s
f :: (Int -> r) -> s -> Int -> F r s
f a b x = f (a x) b
This has the effect of recursing on the type of a until it's of the form Int. Then, we'll use a similar instance to recurse on the type b :: Int -> s:
instance VarArgs Int s => VarArgs Int (Int -> s) where
type F Int (Int -> s) = Int -> F Int s
f :: Int -> (Int -> s) -> Int -> F Int s
f a b x = f a (b x)
Ultimately, both functions will be reduced to 0-ary functions of type a, b :: Int, and we can use the terminal instance:
instance VarArgs Int Int where
type F Int Int = Int
f :: Int -> Int -> Int
f a b = a + b
Here's a little test to prove it works:
times2 :: Int -> Int -> Int
times2 x y = x * y
times3 :: Int -> Int -> Int -> Int
times3 x y z = x * y * z
foo :: [Int]
foo = [ f times2 times2 1 2 3 4
, f times2 times3 1 2 3 4 5
, f times3 times2 1 2 3 4 5
, f times3 times3 1 2 3 4 5 6]
and loading this into GHCi gives:
> foo
[14,62,26,126]
>
Generalizing this to be polymorphic in any Num type doesn't seem to be straightforward. Replacing the Int type with a constrained Num n type leads to errors regarding conflicting family instance declarations.
f a b :: (Int,Int,Int) -> Intorf a b :: Int -> Int -> Int?)n_ainputs isVec n_a X -> Ywheredata Vec n a where Nil :: Vec 0 a; Cons ::a -> Vec n a -> Vec (1 + n) a.f a bto have either of those types, becausef a bmight take any number of inputs. However I think the intention of the puzzle is for a curried function, because having a tuple of arbitrary size is clearly impossible in Haskell. (That being said currying in this way might be impossible, I'm just not sure of that in the way I am sure taking arbitrary tuples won't work)Vecabove or some kind of typed homogeneous tuple-list hybrid. That clears things up.