As mentioned in the comments, you can't have a function to which you'd pass the arity of the function you want to flip. Parameters are computed at runtime, while you need the value at compile time so that you can determine the correct type.
Neither you can make it without passing it the arity somehow. For example a -> b -> c -> d
could be viewed as a function of three arguments returning d
, or as a function if two arguments returning c -> d
.
Probably the easiest solution would be to define the functions explicitly, like flip2
, flip3
etc. I know this isn't what you're looking for, but it's the most practical solution.
Another option would be to use Template Haskell. Then, the situation is different, because Template Haskell executes (I'd say "meta-") code at compile time. With TH you can create a function that takes a natural number and produces a TH expression that can be compiled into another module. The meta-function could be defined as
{-# LANGUAGE TemplateHaskell #-}
module GenFlipTH where
import Language.Haskell.TH
pull :: Int -> Q Exp
pull 0 = varE 'flip
pull n | n < 0 = fail "Negative arity"
| otherwise = [| fmap $(pull (n - 1)) . flip |]
-- Here we use the fact that `(->) r` is a functor.
and used in another module to generate the appropriate expression like
{-# LANGUAGE TemplateHaskell #-}
import GenFlipTH
flip3 :: (a -> b3 -> b2 -> b1 -> b -> c) -> (b3 -> b2 -> b1 -> b -> a -> c)
flip3 = $( pull 3 )
This is probably closes to your requirements I can get - you determine the function by a number and get compile-time guarantees that it's created and used correctly.