是否有一个函数的名称,它接受一个数据和一个函数列表,并将每个函数应用于最后一个函数的结果?

时间:2012-03-03 11:37:44

标签: function haskell clojure functional-programming ocaml

Clojure有一个宏->,它接受​​一段数据和一堆函数,将数据应用到第一个函数,然后将结果应用到下一个函数,结果为< em> 到第三个,依此类推,最后给你回到最后一个申请的结果。

我非常喜欢这个,因为它不是必须从应用它们的顺序向后编写函数,如下所示:(伪代码跟随)

floor (square.root (x))

您可以按照数据流经它们的顺序编写它们:

-> x (square.root, floor)

我的问题是,在函数式语言中是否有这个函数的标准名称,map,reduce和filter有标准名称吗? Clojure文档将其描述为“通过函数线程化数据”,但我在Google上搜索thread这个词时找不到任何内容。我在Haskell中写了一个简单的版本:

thread :: a -> [(a -> a)] -> a
thread x []     = x
thread x (f:fs) = thread (f x) fs

并在Hoogle上搜索a -> [(a -> a)] -> a,但也没有找到任何内容。

在研究这个问题的同时,我还发现你可以使用Haskell中Control.Arrow的函数组合运算符做类似的事情,如下所示:

($2) (sin >>> cos >>> tan)

而使用专用的高阶thread函数,你会写:

thread 2 [sin, cos, tan]

第一种配方是否足以满足实际用途?

6 个答案:

答案 0 :(得分:7)

您要找的名字是function composition

线程宏和comp之间的区别来自前者利用Clojure同音性,而后者更接近于组合的数学定义。

事实上,如果每步创建一个参数的函数,则可以将线程宏调用转换为comp调用,并颠倒函数的顺序:

(defn sin [n] (Math/sin n))
(defn cos [n] (Math/cos n))

(-> 1 sin cos sin cos cos) ; 0.6858966217219662
((comp cos cos sin cos sin) 1) ; 0.6858966217219662

答案 1 :(得分:4)

我认为您可以使用foldl来使用适当的参数:

-- functions for testing
f1 x = x+1
f2 x = x*2
f3 x = x*x
-- here comes the line you're interested in
foldl (\x y -> y x) 2 [f1, f2, f3]

参数如下:

  • (\x y -> y x)是一个函数y,并将其应用于参数x。然后,y将被列表中的每个函数替换。
  • 2是您要为函数提供的初始参数。
  • [f1, f2, f3]是功能列表。

使用这些参数,foldl计算以下内容:f3(f2(f1(2)))

答案 2 :(得分:2)

鉴于>>>类似于bash shell的管道运算符rooted from Unix,我称之为管道序列组合器。

答案 3 :(得分:2)

这不是完全你正在寻找的功能,但这个功能有一个“惯用名”:

foldr (.) id

经验丰富的Haskeller甚至不需要考虑这意味着什么;成为一个单词是很常见的。

foldr (.) id :: [a -> a] -> a -> a
foldr (.) id [abs, succ, negate] 42
    = (abs . succ . negate . id) 42
    = abs (succ (negate 42))

您获取上一个而不是 next 输出的每个函数所要求的功能将是

foldr (.) id . reverse

但是如果你可以管理它,那么使用以前的版本(对于一个版本来说,它更懒惰;即它可以在给定无限函数列表的情况下产生结果)。

答案 4 :(得分:0)

你在haskell中不能有这样的功能,因为它仅限于接受和返回相同类型的函数。这不是很有用。

但你可以使用

功能组成:

floor . sqrt 

或箭头:

sqrt >>> floor

答案 5 :(得分:0)

Oliver Steele在他的Functional Javascript库中将其称为sequencepipe也可能是一个好名字。