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

slmsl1lt  于 2022-11-30  发布在  其他
关注(0)|答案(7)|浏览(133)

Clojure有一个宏->,它接受一段数据和一组函数,将数据应用于第一个函数,然后将第一个函数的结果应用于下一个函数,将 that 的结果应用于第三个函数,依此类推,最后返回上一个应用程序的结果。
我很喜欢这样,因为这样就不必按照应用的顺序反序编写函数,如下所示:(伪代码如下)

floor (square.root (x))

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

-> x (square.root, floor)

我的问题是,在函数式语言中,这个函数是否有一个标准的名称,就像map、reduce和filter有标准的名称一样?Clojure文档将其描述为“通过函数线程化数据”,但我在谷歌上搜索单词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]

第一个公式是否足以实际应用?

qyzbxkaa

qyzbxkaa1#

您要查找的名称是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
qf9go6mv

qf9go6mv2#

我想你可以使用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))) .

px9o7tmv

px9o7tmv3#

假设>>>类似于bash shell的管道操作符rooted from Unix,我将把它称为 pipeline sequence combinator。

vnjpjtjt

vnjpjtjt4#

这并不是您要寻找的函数,但该函数有一个“惯用名称”:

foldr (.) id

一个有经验的Haskeller甚至不需要去想这意味着什么;它是一个词就足够了。

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

如果每个函数都获取 previous 而不是 next 的输出,则您所要求的函数将为

foldr (.) id . reverse

但如果你能管理它,就使用前一个版本(其一,它更懒;即,给定函数的无限列表,它可以产生结果)。

nx7onnlm

nx7onnlm5#

你不能在haskell中有这样的函数,因为它只限于接受和返回相同类型的函数,这不是很有用。
但您可以使用其中一种
功能组成:

floor . sqrt

或箭头:

sqrt >>> floor
i1icjdpr

i1icjdpr6#

奥利弗Steele在他的函数式Javascript库中称之为sequencepipe可能也是一个不错的名字。

xu3bshqb

xu3bshqb7#

和Haskell一样,OCaml的限制是所有涉及的函数都需要接受和返回相同的类型。
h (g (f x))也可以用|>运算符表示为x |> f |> g |> h,所以如果我们以x作为初始值,将运算符折叠到函数列表上,我们就完成了目标。
我们也可以使用Fun.flip来实现函数列表的部分应用。如果涉及的类型是多态的,请注意值限制。

─( 18:06:56 )─< command 19 >─────────────────────────────────────{ counter: 0 }─
utop # let apply v fs = List.fold_left (|>) v fs;;
val apply : 'a -> ('a -> 'a) list -> 'a = <fun>
─( 18:12:43 )─< command 20 >─────────────────────────────────────{ counter: 0 }─
utop # apply 5 [(fun x -> x + 1); (fun x -> x * 3)];;
- : int = 18
─( 18:14:18 )─< command 21 >─────────────────────────────────────{ counter: 0 }─
utop # apply 5 [(fun x -> x + 1); (fun x -> x * 3); (fun x -> x / 2)];;
- : int = 9
─( 18:14:48 )─< command 22 >─────────────────────────────────────{ counter: 0 }─
utop # let f = Fun.flip apply [(fun x -> x + 1); (fun x -> x * 3); (fun x -> x / 2)];;
val f : int -> int = <fun>
─( 18:17:23 )─< command 23 >─────────────────────────────────────{ counter: 0 }─
utop # f 9;;
- : int = 15

相关问题