javascript - JavaScript 中的函数式编程是否可以具有任何类型的多态性?

标签 javascript types functional-programming polymorphism parametric-polymorphism

关闭。这个问题需要更多focused .它目前不接受答案。












想改善这个问题吗?更新问题,使其仅关注一个问题 editing this post .

3年前关闭。




Improve this question




JavaScript 中的函数式编程是否可以具有任何类型的多态性?

我喜欢 FP,但是当我想使用 JS 时,除了使用类/原型(prototype)之外,我无法弄清楚如何在 JS 中支持多态性。

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

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

最佳答案

Javascript 是一种无类型语言

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

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

动态类型语言具有自省(introspection)功能,可以在运行时检查值的类型。但这种手段是有限的。例如,你不能内省(introspection)函数的类型,只要它没有被完全应用。

然而,原始意义上的函数式编程意味着使用许多小的、专门的一阶和高阶函数,这些函数在 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 几乎可以在任何地方执行副作用,这使得创建一个健全且可靠的类型检查器变得非常困难。查看 issues在 Flow 存储库中获取您自己的图片。

将 Javascript 降级为编译目标

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

运行时类型检查器

注意:这是无耻的插件!

作为一种动态类型语言,Javascript 具有成熟的自省(introspection)能力。除了 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的中间类型签名告诉您它期望...
  • 二元函数
  • 一个值
  • 一元函数
  • 和另一个值

  • 那就是你会像 comp1(inc) (1) (add) (2) (3) 一样应用它.
    comp2的中间类型签名告诉您它期望...
  • 一元函数
  • 二元函数
  • 两个值

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

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

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

    关于javascript - JavaScript 中的函数式编程是否可以具有任何类型的多态性?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48257447/

    相关文章:

    JavaScript:单引号 ' 导致错误

    java - 为什么它被假定为 long 没有后缀

    typescript - 省略 TypeScript 中的联合

    javascript - 使用 page-break-inside : avoid wth css or javascript or from browser? 时在分页符时添加页眉

    javascript - 将 Openlayers 3 和 proj4js 与 RequireJS 结合使用

    javascript - 如何在 Javascript 中对每个数组元素运行函数

    types - OCaml : type constraints in signatures

    scala - 有哪些类型级编程的例子?

    swift - 如何在 Swift 中将 "append"设置为不可变字典?

    haskell - 如何在 Haskell 中组合函数和 monad Action