高阶函数,用于输入函数列表和元素列表,并将函数应用于元素

时间:2017-03-27 19:32:27

标签: haskell

正如标题所示,我试图实现一个声明为

的高阶函数
Ord u => [v->u]->[v]->[u]

有输入a)任何类型的函数列表和任何类型的值范围和b)相同类型的元素列表然后它将返回一个列表,该列表是所有发生的元素的结果从给定列表中的函数以递增顺序将给定列表中的元素应用而不重复值。

我试图用折叠功能实现它而没有运气。 我认为我可以将zip函数作为一对进行索引,因此它们将逐个应用于foldr函数。下面我创建了一个插入排序,所以我可以对最终列表进行排序

apply :: Ord u => [v->u]->[v]->[u]             
apply f y = insSort (foldr(\(i, x) y -> x:y ) (zip [1..] f))

insSort :: Ord u => [u] -> [u]
insSort (h:t) = insert h (insSort t)
insSort [] = []

insert :: Ord u => u -> [u] -> [u]
insert n (h:t)
            | n <= h = n : h : t
            | otherwise = h : insert n t
insert n [] = [n]

例如输出的一些输入:

>apply [abs] [-1]
[1]

>apply [(^2)] [1..5]
[1,4,9,16,25]

>apply [(^0),(0^),(\x->div x x),(\x->mod x x)] [1..1000]
[0,1]

>apply [head.tail,last.init] ["abc","aaaa","cbbc","cbbca"]
"abc"

> apply [(^2),(^3),(^4),(2^)] [10]
[100,1000,1024,10000]

>apply [(*5)] (apply [(‘div‘5)] [1..100])
[0,5,10,15,20,25,30,35,40,45,50,55,60,65,70,75,80,85,90,95,100]

1 个答案:

答案 0 :(得分:3)

apply :: [a -> b] -> [a] -> [b]

首先,此签名与标准<*>函数的签名匹配,该函数是Applicative类的一部分。

class Applicative f where
    pure :: a -> f a
    (<*>) :: f (a -> b) -> f a -> f b

设置f ~ []我们有<*> :: [a -> b] -> [a] -> [b]

至少有两种明智的方法可以为列表编写Applicative实例。第一个采用其输入的笛卡尔积,将每个函数与每个值配对。如果<*>的输入列表的长度为 N M ,则输出列表的长度为 N * M 。此规范的pure会将元素放在单例列表中,以便pure id <*> xs = xs

instance Applicative [] where
    pure x = [x]
    (f:fs) <*> xs = map f xs ++ (fs <*> xs)

这相当于the standard Applicative instance for []

实现Applicative的另一种明智方法是通过逐点将元素应用于元素来将两个列表压缩在一起。如果<*>的输入列表的长度为 N M ,则输出列表的长度为 min(N,M)pure创建了一个无限列表,所以再次pure id <*> xs = xs

instance Applicative [] where
    pure x = let xs = x:xs in xs
    [] <*> _ = []
    _ <*> [] = []
    (f:fs) <*> (x:xs) = f x : (fs <*> xs)

此实例位于the ZipList newtype下的base