高阶函数是什么?

高阶函数是什么?

原文:https://medium.com/hackernoon/higher-order-functions-what-are-they-be74111659e8

在数学和计算机科学中,高阶函数(也称泛函、函数形式或函子;不要与范畴理论中的函子概念相混淆)是一个至少执行以下操作之一的函数:

1。接受一个或多个函数作为参数,

2。返回一个函数作为结果。

这是正式的定义,但是它们到底是什么,我们为什么需要它们?

有时,对数据集的项执行某种操作是很重要的,但是这种特定的操作是在执行时定义的。有时候,除了我们需要在某个特定的点上做些什么之外,没有办法知道我们想要采取什么行动,但这是完全未知的。

让我们看一个例子。

let x = [1..100] for each item in x do
    print(item)

这里,我们通过调用 print 函数来打印列表 x 中的每个数字。如果我们需要对每个项目做些别的事情呢?我们需要实现我们认为会用到的所有可能的情况吗?

让我们定义一个函数,它将被 x 中的每个数字(项目)调用。

let succ (x) -> x + 1

我们已经定义了后继函数,它基本上获取一个值并返回它的后继。 succ 的域是 Int 数,这可以从 succ 的主体中推断出来,因为我们在参数中加了 1,并且我们说 succ 具有类型 Int - > Int。

现在,让我们回顾一下前面的例子。

let map (f, list) = 
    for each item in list do
        f(item)

这里, map 是一个高阶函数,因为它接收了函数 f 作为参数,该函数将对列表中的每一项执行。在我们定义映射的时候,我们不需要知道 f 的值会是什么,除了知道 f 为 type Int - > Some 。没有办法从前面的代码中推断出 f 的返回值,但是我们知道它必须接收一个 Int

另一个例子是返回另一个函数的函数。我们来复习一下。

let plus2 (x) =
    let succ (y) = y + 1

    succ (succ x)

let r = plus2 (1)

在这种情况下, plus2 是一个类型为 Int - > Int - > IntInt->(Int->Int)的函数。它基本上接受一个 Int 并返回一个接受另一个 Int 并返回一个 Int 的函数。评估后,r 将等于 3。

现在我们已经展示了这些类型的函数,让我们看看现代编程语言是如何定义它们的。

Scala 中我们可以定义一个 (a - > b,List[a]) - > List[b] 类型的映射函数如下:

def map[a,b](f: a => b, v: List[a]): List[b] = {
    for ( i <- v )
      yield f(i)
  }

val squares = map( (x: Int) => x * x, 1.to(100).toList )

对于 v 中的每个 i ,我们应用函数 f 并返回其值。变量 squares 将具有从 1 到 100 的数字的平方值。请注意,我们在调用 map 的时候正在定义平方函数,所以 map 对函数 f 一无所知。我们可以很容易地说:

def succ (x: Int): Int = x + 1val successors = map(succ, 1.to(100).toList)

我们只是改变了传递给地图的函数,我们得到了完全不同的结果。这个抽象层次使得 map 作为一个高阶函数非常强大。

即使是非函数式的编程语言,比如 c#,也加入了这些抽象,因此它们可以灵活地用于许多用例。

在 C# 中,我们需要实现一个委托来获得相同的功能,但是它给语言带来了相同的价值。因为高阶或函数非常重要。NET 框架已经实现了一些委托,所以让我们使用它们

List<b> map<a>(Func<a,b> f, List<a> list) 
{
    foreach (a x in list) 
    {
        yield return f(x);
    }
}var successors = map(x => x + 1, someIntList);

我们已经在 Scala 中实现了贴图的相同功能。唯一不同的是 C# 没有更高阶的函数,它必须使用委托构造,然而我们得到了相同的功能。注意,在 C# 中,当我们将 succ 函数传递给 map 时,不需要声明该函数的参数类型,由 C# 来推断!

F# 中,它变得非常有趣,因为语言支持函数式编程(FP)范式。在 F# 中我们做:

let map f = function
    |[]     ->[]
    |h::t   -> (f h) @ (t |> map f) let successors = [1..100] |> map (fun x -> x + 1)

看起来很复杂,但实际上它与我们之前看到的地图是一样的。唯一增加的是函数式编程风格和尾部递归,这是函数式编程语言的典型特征。管道 | > 操作符只是一个语言构造,我们可以说 map f tmap (fun x - > x + 1) [1..100] 。注意,类型推理系统在 F# 中工作得相当好。我们没有定义任何类型;然而,映射被推断为接收一个函数和一个列表,并返回一个转换的列表。

F# 中的加 2 功能如下:

let plus2 x = 
    let succ y = y + 1  
    succ succ y

对于一些人来说,高阶函数在他们的生活中很常见。这些函数内置于许多语言和框架中;尽管如此,我还是看到了他们周围的一些困惑。不支持它们的语言需要找到有时不容易使用和实现的替代方法。 C 语言使用指向函数的指针, C# 使用委托其他语言使用对象作为替代。另一方面,有些产品支持开箱即用的高阶功能。 ScalaPythonF# 只是几个例子。

即使有时我们使用这些函数时没有考虑太多,我们也应该知道它们是如何实现的,这样我们就可以从中受益更多。那些对我们从λ演算继承的这种编程结构不熟悉的人应该学习它们并熟悉它们,因为函数式编程的趋势似乎正在赢得一些战斗。高阶函数是 FP 语言的支柱之一,这似乎是未来的趋势。

黑客中午是黑客如何开始他们的下午。我们是阿妹家庭的一员。我们现在接受投稿并乐意讨论广告&赞助的机会。

要了解更多信息,请阅读我们的“关于”页面、喜欢/在脸书上给我们发消息,或者简单地发送 tweet/DM @HackerNoon。

如果你喜欢这个故事,我们推荐你阅读我们的最新科技故事趋势科技故事。直到下一次,不要把世界的现实想当然!


本站为非盈利网站,作品由网友提供上传,如无意中有侵犯您的版权,请联系删除