好吧,正如你自己注意到它实际上是不可能的,因为不同的列表长度(对于类型系统是不可见的)会导致不同的类型.唯一"可靠"的方法就是使用某种编译时列表; 各种各样,但没有一个真正稳定支持和易于使用.
最简单的替代方法是将参数作为列表.即
ifxChain :: [a->a->a] -> [a] -> a
这个可以轻松实现:它基本上是一个zip,为每个函数提供第二个参数,省略第一个参数.然后通过结果的单参数函数列表折叠第一个参数:
ifxChain fs (p0:ps) = foldl' (flip ($)) p0 $ zipWith flip fs ps
您可能希望添加具有不匹配长度的列表的处理,应该是合理安全的.
如果你坚持实际可变数量的函数参数(我认为这不好!)那么你需要一些类型类hackery.这种可变函数最为人所知printf
.
{-# LANGUAGE MultiParamTypeClasses #-} {-# LANGUAGE FlexibleInstances #-} class ChainedFunc f t where chainIfxs :: [t->t->t] -> t -> f chainIfxs fs i = chainIfxPre i id $ reverse fs chainIfxPre :: t -> (t->t) -> [t->t->t] -> f instance ChainedFunc t t where chainIfxPre i f [] = f i instance (ChainedFunc f t) => ChainedFunc (t->f) t where chainIfxPre i fin (f:fs) x0 = chainIfxPre i (flip f x0 . fin) fs
显然,这在很多方面都不好看.但是,嗯,它有效......啊......
Main> chainIfxs [(*),(+),( - )](2 :: Int)(3 :: Int)(4 :: Int)(5 :: Int):: Int
15