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]
第一种配方是否足以满足实际用途?
答案 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库中将其称为sequence
。 pipe
也可能是一个好名字。