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.
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.
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With