【问题标题】:Is it possible to have any kind of polymorphism with Functional Programming in JavaScript? [closed]JavaScript 中的函数式编程是否可以具有任何类型的多态性? [关闭]
【发布时间】:2018-06-23 18:09:48
【问题描述】:

是否有可能在 JavaScript 中使用函数式编程实现任何类型的多态性?

我喜欢 FP,但是当我想使用 JS 时,除了使用类/原型之外,我不知道如何在 JS 中支持多态性。

例如如何在JS中用FP实现toString?

使用 OOP,我可以简单地重载 toString,以便 object.toString() 执行特定于 object 或其原型的 toString 代码。

【问题讨论】:

  • 我不确定您的问题是否清楚。我不明白你是要实现返回字符串的函数还是什么?
  • 给出更多的上下文,你想达到什么。 !
  • 查看here 了解鸭子类型。
  • @AliShakiba - 我知道 toString 做什么,我不明白你想做什么。
  • 在 Haskell 中,每种可转换为字符串的类型都有一个 show 实例。编译器会选择正确的(或者在没有的时候对你大喊大叫)。因此编译器有效地包含一个数据结构,它将已知数据类型映射到show 的已知实例,并运行编译时类型检查以选择合适的函数。在 JS 中你不能在编译时这样做,但你当然可以创建这样的数据结构(一个神奇的全局)并在运行时模仿行为。

标签: javascript types functional-programming polymorphism parametric-polymorphism


【解决方案1】:

函数上下文中的多态性意味着具有相同名称但具有不同参数类型的函数调用根据参数类型调用不同的函数。这意味着必须根据参数类型进行分派。您可以在运行时使用typeof 和instanceof 语法在JS 中进行这种调度。但这被认为对于通用用途来说太慢了。大多数现代功能方法(ML、Haskell)使用type inference 实现编译时调度。这仅对编译时间有影响,但对执行时间没有影响。但是 JavaScript 是像 Scheme 这样的传统函数式语言,具有固定的对象系统,没有宏。

所以答案是:不,在 JS 中不可能有任何类型的多态性。

【讨论】:

    【解决方案2】:

    Javascript 是一种无类型语言

    不,Javascript 没有多态性的概念,因为它是一种无类型语言。简单地说,多态意味着严格的类型系统在受控条件下不那么严格,也就是说,它不会因为多态的行为而失去类型安全。

    无类型语言虽然有些简化。从静态类型系统的角度来看,Javascript 有一个巨大的联合类型,一个值或其底层表达式可以在运行时采用它的任何表示形式(变量甚至可以在它们存在期间适应不同的类型)。这种类型也称为动态类型。

    动态类型语言具有在运行时检查值类型的自省功能。但这种手段是有限的。例如,只要没有完全应用函数,您就无法内省函数的类型。

    但是,原始意义上的函数式编程意味着使用大量小的、专门的一阶和高阶函数,这些函数在curried form 中声明。这种方法会导致在您的代码中部分应用函数。现在的问题是,您不仅要推断初始函数的类型,还要推断部分应用函数的中间类型。这很快就会变得艰难:

    // what's the type of this function?
    
    const comp = f => g => x => f(g(x));
    
    
    // and this partially applied one?
    
    const inc = n => n + 1;
    comp(inc);
    
    
    // and even worse:
    
    comp1 = comp(comp);
    comp2 = comp(comp) (comp);
    

    我确定我在字里行间的某个地方迷失了你。从头脑中推断出这些类型需要很多时间。作为一名开发人员,你真的应该有责任像编译器一样行事吗?我不这么认为。

    问题的替代解决方案

    幸运的是,Javascript 社区一直在积极开发此类问题的解决方案。

    语言之上的静态类型检查器

    Flow 和 TypeScript 是静态类型检查器,它们试图将类型系统添加到 Javascript 中。我个人认为这不是一个有前途的方法,因为通常在创建新语言时首先设计类型系统。 Javascript 可以在任何地方执行副作用,这使得创建一个健全可靠的类型检查器变得非常困难。查看 Flow 存储库中的 issues 以获得您自己的图片。

    将 Javascript 降级为编译目标

    是的,这个标题可能有点基于意见,但这就是我的感觉。 Elm、purescript、Facebook 的Reason 就是这种方法的代表。好吧,如果你想放弃 Javascript,这些都是合理的可能性。但是赌哪匹马呢? Javascript 生态系统的碎片化真的很可取吗?还是我们想要一个依赖像 Facebook 这样的供应商的社区?我无法真正回答这个问题,因为我有很大的偏见,正如你即将看到的那样。

    运行时类型检查器

    注意:这是一个无耻的插件!

    作为一种动态类型语言,Javascript 具有成熟的自省功能。除了 ES2015 代理之外,我们还拥有构建虚拟化运行时类型检查器所需的一切。在这种情况下,虚拟意味着它是可插拔的,即您可以打开和关闭它。运行时类型系统需要是可插拔的,因为它对性能有重大影响,并且仅在开发阶段才需要。

    我已经为这样的类型检查器工作了几个月,到目前为止,这是一段令人兴奋的旅程。 ftor 远非稳定,但我相信这种方法值得探索。

    这是上面的 comp 组合子,作为带有类型提示的类型化版本(TS 只是一个内部 Symbol,它包含一个类型的当前签名,您可以使用它来请求此签名以进行调试):

    import * as F from ".../ftor.js";
    
    
    F.type(true);
    
    
    const comp = F.Fun(
      "(comp :: (b -> c) -> (a -> b) -> a -> c)",
      f => g => x => f(g(x))
    );
    
    
    const inc = F.Fun(
      "(inc :: Number -> Number)",
      n => n + 1
    );
    
    
    comp(inc) [TS]; // "(comp :: (a -> Number) -> a -> Number)"
    
    
    const comp1 = comp(comp),
      comp2 = comp(comp) (comp);
    
    
    comp1 [TS]; // "(comp :: (a -> b0 -> c0) -> a -> (a0 -> b0) -> a0 -> c0)"
    
    
    comp2 [TS]; // "(comp :: (b1 -> c1) -> (a0 -> a1 -> b1) -> a0 -> a1 -> c1)"
    

    comp1 的中间类型签名告诉你它期望...

    1. 二元函数
    2. 一个值
    3. 一元函数
    4. 还有另一个值

    也就是说,您可以像 comp1(inc) (1) (add) (2) (3) 一样应用它。

    comp2 的中间类型签名告诉你它期望...

    1. 一元函数
    2. 二元函数
    3. 两个值

    您可以像comp2(inc) (add) (2) (3) 一样应用它。所以comp2实际上是有用的,因为它允许我们应用一个二元函数作为组合的内部函数。

    诚然,如果您不熟悉这些类型签名,则很难阅读它们。但根据我的经验,学习曲线相当短。

    ftor 支持参数和行多态,但目前不支持 ad-hoc。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2013-03-28
      • 1970-01-01
      • 2012-11-08
      • 2021-07-28
      • 1970-01-01
      • 2011-02-04
      • 2015-09-09
      • 1970-01-01
      相关资源
      最近更新 更多