因此,如果一种语言提供更高阶的程序,那么我可以拥有返回程序的程序。类似的东西:

(define (Proc a b c)
  (lambda (x) ( #| method body here in terms of a b c and x |# )))

要创建新程序,我会做类似的事情:

(define ProcA (Proc a1 b1 c1)) ; Would create ProcA that has 1 argument

类似的任务可以用不支持高阶过程的语言来完成,方法是定义 Proc ,它取4个而不是3个参数,并调用这个过程来定义 ProcA ,像:

(define (Proc a b c x) ( #| method body -- does not return any procedure |# )
(define (ProcA x) (Proc a1 b1 c1 x))

那么为什么有关高阶程序的模糊呢?我错过了什么吗?

有帮助吗?

解决方案

很好地观察到返回另一个函数的函数与带有两个参数的函数相同。这称为“Currying”。换句话说,从A到B的函数是逻辑蕴涵的证明,A暗示B或:

A => B.

如你所知,如果A暗示B暗示C,则A和B暗示C或:

(A => (B => C)) <==> ((A, B) => C)

但是更高阶函数不一定是返回另一个函数的函数。 高阶函数是一个以另一个函数作为参数的函数。这是一个重要的区别,HOF是非常强大的编程工具。

例如,考虑一下这个Haskell函数:

map :: (a -> b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : (map f xs)

这个高阶函数接受函数 f 并将其应用于列表中的每个元素。在没有HOF的语言中,您可以使用循环或类似的功能执行此功能,但是在具有HOF的语言中,您可以使用这样的简单调用为列表中的每个元素调用 f

map f myList

当然,语言中的控件构造可以让您接近高阶函数,但是具有高阶函数的语言可以让您创建自己的控件构造。方案当然有资格。

其他提示

我不会试图在这里概括一下这个论点,但是在为什么功能编程事项,John Hughes认为高阶函数是有用的,因为它们提供了更有效的方法来“粘合在一起”。程序的一部分,从而使重用代码变得更容易。这些例子是一种非常古老的语言,不再使用太多,但它们仍然易于遵循并且非常有说服力。阅读约翰的论文是一个很好的方式来得到你的问题的详细答案“为什么有这么多关于高阶程序的模糊”。

这更多是关于心态而不是可行性。它允许您将功能视为一等公民,并根据功能操作来创建其他功能等。

显然你可以用其他语言来做或模拟它,但是如果它不是一种句法机制,那就被视为一种加法或者一种黑客攻击。

好的,但是在第二个例子中,您在编译时使用预先设定的 a1 b1 c1列表创建该过程。在第一个示例中,当您调用 ProcA 时,您将在运行时创建它,并且您可以根据需要创建任意数量的不同,因此您可以做更多有趣的事情。

通过数组考虑变换函数或排序算法。现在,您希望让它非常灵活,让函数用户通过让函数作为参数传递函数来指定函数的行为。

说,您使用以下程序原型编写排序算法:

sort(Array a, void (*fn)(a::element_type, a::element_type));

该函数的用户可以通过传递适当的fn来指定是否需要降序或升序。

你需要一个内部类来正确地模拟它。第一种情况,Proc是关闭a,b和c。在第二种情况下,ProcA的调用者无法控制a1,b1和c1如何传递给另一个过程,他只能控制x。因此,您控制a1,b1和c1的方式是通过更高范围的使用变量(模块级别或某些此类),这使您的函数不纯。在这种情况下,您无法确保在调用之间给定相同的参数,ProcA将返回相同的结果。与Proc一样,您可以始终确保如果使用相同的参数调用它,则会发生相同的结果。

我在javascript中使用高阶函数,例如,当我使用选择框时。我可以传入将在选择选项时调用的函数,因为我唯一的区别是,这简化了我的代码,减少了冗余。

我在其他支持高阶函数的语言中看到同样的事情,因为我可以开始研究如何清理我的代码,其中有一些可以本地化的冗余,任何差异都可以在一个函数中完成。

一旦C#支持这一点,我知道它现在更加主流。 :)

如果函数接受和/或返回函数,则称为高阶函数(HOF)。对于没有经验的程序员,来自C,C ++或Java,高阶函数听起来像魔术,但它们非常简单。想象一个简单的函数返回2 + 3的结果:

(define (foo) (+ 2 3)) ;; (foo) => 5

这是一个无聊的功能,它总是会增加2到3.如果我们将其概括,那么它不仅会增加2到3,而是添加到任何用户提供的数字?

(define (foo n) (+ 2 n)) ;; (foo 10) => 12

当一种语言不支持高阶函数时,你不得不认为函数和值(例如数字,布尔值,列表)是两个不同的东西。但函数式编程(FP)模糊了它们之间的区别。想象一下,函数和值之间的唯一区别是可以调用一个函数,除了你可以对一个函数做的任何你可以做的 2 #t '(abc):您可以将其作为参数提供,或者从函数返回,或者存储在变量中,或者将其放在列表中。例如,让我们进一步概括我们的小函数,这样不仅可以将2加到 n ,而是将2乘以 n ,或者应用任何其他可以接受两个数字的函数:

(define (foo f n) (f 2 n))
;; (foo + 10) => 12
;; (foo * 10) => 20
;; (foo expt 10) => 1024

当您意识到可以按照处理数字或字符串的方式处理函数时,匿名函数(在FP术语中称为“lambdas”)完全有意义。匿名函数实际上比普通命名函数更基本和“正常”,命名函数只是放入变量的匿名函数,就像我们将一个数字放入变量中多次使用它一样。

(+ 2 2) ;; is no different from:
(let ((a 2)) (+ a a))
(lambda (x y) (* x y)) ;; is no different from:
(define (foo x y) (* x y)) ;; which is an abbreviation for:
(define foo (lambda (x y) (* x y))).

因此,HOF允许我们概括我们的功能,使其超级灵活。如果你看看你的功能,看看它背后的逻辑,你可以意识到,如果某些东西对你的数据进行操作,那么其他东西也可能。如果你将2个数字加在一起,你可以将它们相乘,或相减,或取偶数或其他任何数字。而不是每次为每个案例编写一个新函数,你可以接受一个额外的参数,它必须是一个函数。

在FP中,我们一直使用HOF,例如,在操作列表时。 3个函数是FP的面包和黄油: map filter foldl map 接受带有1个参数的函数,将此函数应用于列表的每个元素,并返回包含已更改元素的新列表。 filter 接受带有1个参数的谓词(返回布尔值的函数),将谓词应用于列表的每个元素,并返回一个新列表,其中包含不满足谓词删除的元素。

(map (lambda (n) (+ n 1)) '(1 2 3 4 5) ;; '(2 3 4 5 6)
(define (foo n) (+ n 1))
(map foo '(1 2 3 4 5)) ;; '(2 3 4 5 6)
(filter (lambda (n) (> n 3)) '(1 2 3 4 5)) ;; '(4 5)
(define (bar n) (> n 3))
(filter bar '(1 2 3 4 5)) ;; '(4 5)

想象一下,你有一个1-arity函数列表 - 再次,你可以用函数做任何你想做的事情,并将它存储在数据结构中 - 你想要将它们全部应用到相同的数字,并且获取结果列表。

(let ((xs (list (lambda (x) (+ x 1))
                (lambda (x) (* x 2))
                (lambda (x) (- x)))))
  (map (lambda (f) (f 10)) xs)) ;; => (11 20 -10)

结论:当编程语言正确支持函数式编程概念时,高阶函数允许灵活性和通用性,这使得代码更强大(你可以

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top