5

The flip function in Haskell is used to switch the positions of the first two arguments of a function:

flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y

Similarly we can write a function to rotate three arguments:

rot :: (a -> b -> c -> d) -> b -> c -> a -> d
rot f y z x = f x y z

Can this concept be extended to functions which curry arbitrary number of arguments?

Given a function of type a -> ... -> z is it possible to write a function of the following type?

(a -> ... -> z) -> ... -> a -> z

I know that the -> operator is right associative. Hence ... -> z can't be split. Nevertheless, I would like to know for sure.

2 Answers 2

7

You're right, you can't do this. You'd have to pattern match against an arbitrary number of arguments, and there's no way to do that.

You could use Template Haskell to generate a set of rotate functions for different arities, but you'd always have to decide how many to generate in advance and it wouldn't be a truly generic function, just a shortcut for writing them.

You could do something like it if your functions happened to take their arguments as lists (eew), but that also has the notable disadvantage of requiring the argument types to be homogenous.

Sign up to request clarification or add additional context in comments.

1 Comment

You might be able to do it if they took their arguments as HLists... but thinking about how to do it makes me cringe.
2

Well, technically rot could be (but probably shouldn't) implemented using IncoherentInstances extension:

{-# LANGUAGE MultiParamTypeClasses, TypeFamilies,
  FlexibleInstances, FlexibleContexts,
  UndecidableInstances, IncoherentInstances #-}    

class Rotable a r where
    rot :: a -> r

instance (r ~ (b -> a -> c)) => Rotable (a -> b -> c) r where
    rot = flip

instance (Rotable (a -> c -> d) r', r ~ (b -> r')) => Rotable (a -> b -> c -> d) r where
    rot f b = rot (`f` b)

Example of usage:

*Main> rot (-) 1 2
1
*Main> :t rot foldr
rot foldr :: b -> [a] -> (a -> b -> b) -> b
*Main> :t (rot . rot) foldr
(rot . rot) foldr :: [a] -> (a -> b -> b) -> b -> b
*Main> (rot . rot) foldr [1..5] (+) 0
15

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.