【问题标题】:Is Ruby a functional language?Ruby 是函数式语言吗?
【发布时间】:2008-10-01 21:16:13
【问题描述】:

Wikipedia 说 Ruby 是一种函数式语言,但我不相信。为什么或为什么不?

【问题讨论】:

标签: ruby functional-programming


【解决方案1】:

一种语言是否是函数式语言并不重要。函数式编程是一篇论文,Philip Wadler(函数式编程的本质)和 John Hughes(为什么函数式编程很重要)解释得最好。

一个有意义的问题是,“Ruby 是否适合实现函数式编程的论点?”答案是“很差”。

我最近就这个问题做了一个演讲。 Here are the slides.

【讨论】:

  • 您提供的幻灯片没有提到为什么 Ruby“非常难以实现 FP 的论点”。为什么 C# 比 Java 更适合(好吧,更简单的匿名函数?)?是因为你可以在 Ruby 中拥有全局变量吗?
  • 不,幻灯片不会详细介绍,因为这是一个相当广泛的主题。例如,冒着过度简化的风险,Ruby 强制执行一个评估模型(按值调用),以确保程序的非组合性。这种情况的影响很容易被低估。 Ruby 还与程序是一系列效果的想法相结合。也就是说,Ruby 竭尽全力使使用任何其他计算模型变得困难/难以处理。我希望这个简短的评论会有所帮助。
  • +1 用于指出将语言分类为功能性语言的歧义。见鬼,我写了函数式 C!
  • 为什么 C# 比 Ruby 更适合?
  • 实际上是一个仅链接的答案,因为它将解释的关键部分(实际上是整个解释)外包给了外部链接。既然链接死了,答案就变得毫无用处了。
【解决方案2】:

Ruby 确实支持更高级的函数(请参阅 Array#map、inject 和 select),但它仍然是一种命令式、面向对象的语言。

函数式语言的关键特征之一是它避免了可变状态。函数式语言没有 Ruby、C、Java 或任何其他命令式语言中的变量概念。

函数式语言的另一个关键特征是它侧重于根据“什么”而不是“如何”来定义程序。在使用 OO 语言进行编程时,我们编写类和方法以将实现(“如何”)从“什么”(类/方法名称)中隐藏起来,但最终这些方法仍然是使用一系列语句编写的。在函数式语言中,您无需指定执行顺序,即使在最低级别也是如此。

【讨论】:

  • 我同意你的大部分陈述,但是,我不同意“函数式语言没有像 Java 等那样的变量概念。”在haskell中,可以在纯函数中使用变量,甚至可以将函数赋值给变量,最大的不同是变量一旦赋值后就不能再修改了。
  • HHC,根据定义,变量是可以改变的值。你说的是价值观。
  • 确实 Haskell 的“不可修改的变量”只是没有参数(定义)的常量函数。
【解决方案3】:

我绝对认为您可以在 Ruby 中使用函数式样式。

能够以函数式编程的最关键方面之一是该语言是否支持更高阶的函数...... Ruby 支持。

也就是说,用 Ruby 进行非函数式编程也很容易。函数式风格的另一个关键方面是没有状态,并且有真正的数学函数,对于给定的一组输入总是返回相同的值。这可以在 Ruby 中完成,但它不像 Haskell 等功能更严格的语言那样在语言中强制执行。

所以,是的,它支持函数式风格,但它也可以让你以非函数式风格进行编程。

【讨论】:

  • 使用这个标准,你会说 Smalltalk 是功能性的,因为它有块吗?
  • 很好的答案,但有一个挑剔 - 高阶函数不是函数式风格严格要求的。例如您可以通过定义函数对象并组合它们来获得与高阶函数相同的效果,从而在 Java 中实现函数式风格(没有一等/高阶函数)。
  • 只是,想声明@peter 问了Is ruby a functional language?,并且直接回答是一个简单的不。 Ruby 是一种面向对象的语言,具有一些功能特性。
【解决方案4】:

我认为支持或能够以函数式风格的语言进行编程并不是函数式语言。

如果我想在几个月几周后伤害我的同事和我自己,我什至可以编写函数式的 Java 代码。

拥有一门函数式语言不仅仅关乎你可以做什么,例如高阶函数、一等函数和柯里化。这也是关于你不能做的事情,比如纯函数中的副作用。

这很重要,因为它是函数式程序或通用函数式代码更易于推理的重要原因。当代码更容易推理时,错误会变得更浅,并漂浮到可以修复的概念表面,从而减少错误代码。

Ruby 的核心是面向对象的,因此尽管它对函数式风格有相当好的支持,但它本身并不是函数式语言。

无论如何,这是我的非科学观点。

编辑: 回想起来,考虑到到目前为止我收到的关于这个答案的优秀 cmets,我认为面向对象与功能比较是苹果和橘子之一。

真正的区别在于执行是否具有权威性。函数式语言将表达式作为其主要语言结构,执行顺序通常未定义或定义为惰性。严格执行是可能的,但仅在需要时使用。在一种指示性语言中,严格执行是默认设置,虽然延迟执行是可能的,但这样做通常很笨拙,并且在许多边缘情况下可能会产生不可预测的结果。

现在,那是我的非科学观点。

【讨论】:

  • 我认为调用 Ruby 函数式比 Java 更好……不,Ruby 并不是严格意义上的函数式,但是在其中使用函数式风格很容易……并且非功能性风格的同事可以轻松将其改回非功能性
  • 是的,Mike,如果您想以函数式风格编写代码,那么 Ruby 是对 Java 的巨大改进。我只是在使用 Java 来夸大和强调这一点。
  • 既然 D 有纯函数,你会称 D 为函数式语言吗? digitalmars.com/d/2.0/function.html#pure-functions
  • 很多人考虑使用 Lisp 和 Scheme 函数式语言,主要是因为匿名函数的普遍使用。然而,它们缺乏有保证的纯函数。将该术语限制为支持纯函数的语言似乎过于严格。
【解决方案5】:

Ruby 必须满足以下要求才能“真正”发挥作用。

不可变值:一旦设置了“变量”,就无法更改。在 Ruby 中,这意味着您必须有效地将变量视为常量。语言不完全支持,您必须手动冻结每个变量。

无副作用:当传递给定值时,函数必须始终返回相同的结果。这与具有不可变的值密切相关。函数永远不能取值并更改它,因为这会导致与返回结果相切的副作用。

高阶函数:这些函数允许函数作为参数,或使用函数作为返回值。可以说,这是任何函数式语言最关键的特性之一。

柯里化:由高阶函数启用,柯里化将一个接受多个参数的函数转换为一个接受一个参数的函数。这与偏函数应用相辅相成,后者将多参数函数转换为比原来使用更少参数的函数。

递归:通过从自身内部调用函数来循环。当您无法访问可变数据时,递归用于构建和链接数据构造。这是因为循环不是一个函数概念,因为它需要传递变量来存储循环在给定时间的状态。

延迟评估或延迟评估:延迟处理值直到实际需要它的那一刻。例如,如果您有一些代码在启用延迟评估的情况下生成斐波那契数列,则在结果中的一个值被另一个函数(例如 puts)需要之前,实际上不会处理和计算。

建议(只是一个想法) 我会很高兴有某种定义来使用mode 指令来声明具有功能范式的文件,例如

模式'功能'

【讨论】:

  • 不客气。我想邀请您阅读有关函数式语言的内容。 Lisp 是所有功能语言、ML(CAML) 和 Erlang/Elixir 的祖父。它真的改变了你对事物的看法。我不是专家,但我一直是计算机科学专业的学生,​​喜欢阅读和学习新东西。
  • 组织良好的答案。本来希望对 ruby​​ 对这些东西的支持程度进行一些额外的探索。我相信高阶函数、柯里化和递归都支持/可能在 ruby​​ 中,如果我错了,请纠正我。
【解决方案6】:

Ruby 是一种支持函数式编程风格的多范式语言。

【讨论】:

    【解决方案7】:

    Ruby 是一种面向对象的语言,可以支持其他范式(函数式、命令式等)。然而,由于 Ruby 中的一切都是对象,所以它主要是一种 OO 语言。

    示例:

    "hello".reverse() = "olleh",每个字符串都是一个字符串对象实例等等。

    阅读herehere

    【讨论】:

    • 我从来没有真正理解过“一切都是对象”如何让 Ruby 更加面向对象。我确实同意 Ruby 主要是面向对象的,但“一切都是对象”实际上仅意味着没有“原始”类型,这对开发人员以 OO 样式编写程序的能力几乎没有影响,因为原始的存在types 一般只是表示有四五种类型没有任何方法。
    【解决方案8】:

    这取决于您对“函数式语言”的定义。就个人而言,我认为这个词在用作绝对词时本身就很成问题。作为“功能语言”的更多方面不仅仅是语言功能,而且大部分取决于您从哪里查看。例如,语言周围的文化在这方面非常重要。它是否鼓励实用风格?可用的库呢?他们是否鼓励您以实用的方式使用它们?

    例如,大多数人会将 Scheme 称为函数式语言。但是 Common Lisp 呢?除了多/单命名空间问题和保证尾调用消除(一些 CL 实现也支持,具体取决于编译器设置),没有什么能让 Scheme 作为一种语言比 Common 更适合函数式编程Lisp,而且大多数 Lispers 不会将 CL 称为函数式语言。为什么?因为围绕它的文化在很大程度上依赖于 CL 的命令式特性(例如 LOOP 宏,大多数 Schemers 可能会皱眉头)。

    另一方面,C 程序员可能会认为 CL 是一种函数式语言。毕竟,用任何 Lisp 方言编写的大多数代码在风格上肯定比你通常的 C 代码块更具功能性。同样,与 Haskell 相比,Scheme 在很大程度上是一种命令式语言。因此,我认为永远不会有明确的是/否答案。是否将语言称为函数式很大程度上取决于您的观点。

    【讨论】:

    【解决方案9】:

    我认为,Ruby 也不是真正意义上的多范式语言。想要将自己喜欢的语言标记为在许多不同领域有用的东西的人往往会使用多范式。

    我认为 Ruby 是一种面向对象的脚本语言。是的,函数是一流的对象(有点),但这并不能真正使它成为一种函数式语言。 IMO,我可能会补充。

    【讨论】:

    • 语言的类型由它支持的编程风格定义;反过来,这又取决于它所具有的功能。一流的和匿名的函数 = 最小的函数式编程。 Ruby 支持 OO 编程但不需要它:您永远不需要定义一个类。因此,多范式。
    【解决方案10】:

    递归在函数式编程中很常见。几乎所有语言都支持递归,但如果没有 tail call 优化 (TCO),递归算法通常是无效的。

    函数式编程语言能够优化尾递归,并且可以在恒定空间中执行此类代码。一些 Ruby 实现确实优化了尾递归,而另一些则没有,但通常 Ruby 实现不需要进行 TCO。见Does Ruby perform Tail Call Optimization?

    因此,如果您编写一些 Ruby 函数式风格并依赖某个特定实现的 TCO,那么您的代码在另一个 Ruby 解释器中可能非常无效。我认为这就是为什么 Ruby 不是函数式语言(Python 也不是)的原因。

    【讨论】:

    • TCO 很有趣,因为它本质上改变了程序的行为。在某些情况下,这对程序是不可见的,但在其他情况下,它是,例如异常回溯。因此,它并不总是适当的优化。
    【解决方案11】:

    严格来说,将一种语言描述为“功能性”是没有意义的;大多数语言都能够进行函数式编程。甚至 C++ 也是。

    函数式风格或多或少是命令式语言特性的子集,支持语法糖和一些编译器优化,如不变性和尾递归展平,

    后者可以说是次要的特定于实现的技术性,与实际语言无关。 x64 C# 4.0 编译器会进行尾递归优化,而 x86 编译器不会出于任何愚蠢的原因。

    语法糖通常可以在某种程度上得到解决,特别是如果该语言具有可编程预编译器(即 C 的#define)。

    问“语言 __ 是否支持命令式编程?”可能更有意义,而答案(例如 Lisp)是“不”。

    【讨论】:

      【解决方案12】:

      请看书的开头:"A-Great-Ruby-eBook"。它讨论了您要问的非常具体的主题。您可以在 Ruby 中进行不同类型的编程。如果你想像功能一样编程,你可以做到。如果你想像命令式那样编程,你可以做到。这是一个定义问题,Ruby 到底有多实用。请看用户camflan的回复。

      【讨论】:

        猜你喜欢
        • 2020-05-12
        • 2010-09-17
        • 2011-04-27
        • 1970-01-01
        • 2011-09-04
        • 1970-01-01
        • 2011-01-17
        • 2011-03-11
        • 2011-11-09
        相关资源
        最近更新 更多