Haskell中的flip
函数用于切换函数前两个参数的位置:
flip :: (a -> b -> c) -> b -> a -> c
flip f y x = f x y
同样,我们可以编写一个函数来旋转三个参数:
rot :: (a -> b -> c -> d) -> b -> c -> a -> d
rot f y z x = f x y z
这个概念可以扩展到讨论任意数量的参数的函数吗?
给定a -> ... -> z
类型的函数是否可以编写以下类型的函数?
(a -> ... -> z) -> ... -> a -> z
我知道->
运算符是正确关联的。因此... -> z
无法拆分。不过,我想肯定地知道。
答案 0 :(得分:6)
你是对的,你不能这样做。你必须对任意数量的参数进行模式匹配,并且没有办法做到这一点。
你可以使用Template Haskell为不同的arities生成一组旋转函数,但是你总是必须先决定要生成多少个旋转函数,它不是真正的通用函数,只是写入它们的快捷方式
如果你的函数碰巧把它们的参数作为列表(eew),你可以做类似的事情,但是这也有一个显着的缺点,就是要求参数类型是同质的。
答案 1 :(得分:2)
嗯,技术上rot
可能(但可能不应该)使用IncoherentInstances
扩展程序实现:
{-# 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)
使用示例:
*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