5

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不能拆分。不过,我很想知道。

4

2 回答 2

7

你是对的,你不能这样做。您必须针对任意数量的参数进行模式匹配,而且没有办法做到这一点。

您可以使用 Template Haskell 为不同的 arities 生成一组旋转函数,但您总是必须提前决定要生成多少个,它不是一个真正的通用函数,只是编写它们的快捷方式。

如果你的函数碰巧将它们的参数作为列表(eew),你可以做类似的事情,但这也有一个明显的缺点,即要求参数类型是同质的。

于 2013-03-14T10:57:03.457 回答
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
于 2013-03-15T01:38:55.570 回答