JavaScript中的函数编程是否可能存在任何类型的多态性?

JavaScript中的函数编程是否可能存在任何类型的多态性?,javascript,types,functional-programming,polymorphism,parametric-polymorphism,Javascript,Types,Functional Programming,Polymorphism,Parametric Polymorphism,JavaScript中的函数编程是否可能存在任何类型的多态性 我喜欢FP,但当我想使用JS时,除了使用类/原型之外,我不知道如何在JS中支持多态性 例如,如何在JS中实现FP 使用OOP,我可以简单地重载toString,以便object.toString()执行特定于对象或其原型的toString代码。函数上下文中的多态性表示具有相同名称但具有不同参数类型的函数调用根据参数类型调用不同的函数。这意味着必须根据参数类型进行分派。您可以在运行时使用和语法在JS中执行此类调度。但这被认为对于一般用途

JavaScript中的函数编程是否可能存在任何类型的多态性

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

例如,如何在JS中实现FP


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

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

所以答案是:不,JS中不可能有任何形式的polimorphism。

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

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

动态类型语言具有内省功能,可以在运行时检查值的类型。但这一手段是有限的。例如,只要函数没有完全应用,就不能对其类型进行内省

然而,函数式编程在最初的意义上意味着使用许多小的、专门的一阶和高阶函数,这些函数在中声明。这种方法会在代码中产生部分应用的函数。现在的问题是,不仅要推导初始函数的类型,还要推导部分应用函数的中间类型。这将很快变得艰难:

// 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可以在任何地方执行副作用,这使得创建一个可靠的类型检查器非常困难。查看流存储库中的,以获得您自己的图片

将Javascript降级为编译目标

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

运行时类型检查器

注意:这是一个无耻的插头

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

我已经在这样一个类型检查器上工作了几个月了,到目前为止,这是一个激动人心的旅程。虽然还远远不够稳定,但我相信这种方法值得探索

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

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

  • 二元函数
  • 价值
  • 一元函数
  • 还有另一个价值
  • 也就是说,您可以像
    comp1(inc)(1)(add)(2)(3)
    一样应用它

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

  • 一元函数
  • 二元函数
  • 两个价值观
  • 您可以像
    comp2(inc)(add)(2)(3)
    一样应用它。因此,
    comp2
    实际上很有用,因为它允许我们应用二进制函数作为构图的内部函数

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


    ftor支持参数多态性和行多态性,但目前不是特别的。

    我不确定您的问题是否清楚。我不明白您是想实现返回字符串的函数还是什么?给出
    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)"