JavaScript 中的函数式编程风格模式匹配

Functional programming style pattern matching in JavaScript

我正在编写从函数式语言到 JS 的编译器。编译器将在浏览器中 运行。我需要在 JS 中实现模式匹配机制,因为原始语言有一个。我找到了 Sparkler and Z。据我所知,Sparkler 无法在浏览器中执行,Z 也没有我需要的所有可能性。

所以我的语言有这样的语义:

count x []         <- 0
count x [ x : xs ] <- 1 + count x xs
count x [ y : xs ] <- count x xs

这就是这段代码中发生的事情:

第一行是一个函数的定义,它有两个参数:一些变量 x 和空列表,以及 returns 零。

第二行是一个函数的定义,它也有两个参数:一些变量x和以x开头的列表,以及returns 1 + count(x, xs)

对于这个例子,我想生成这样的代码:

const count = (x, list) => {
    match(x, list) => (
        (x, []) => {...}
        (x, [ x : xs ]) => {...}
        (x, [ y : xs ]) => {...}
    )
} 

如何将这种模式匹配正确展开为ifsors

一般情况

proposal for Pattern Matching in ECMAScript,但截至 2018 年还处于非常早期的阶段。

目前,实现部分仅列出:

案例列表

使用destructuring assignment,如:

const count = list => {
  const [x, ...xs] = list;
  if (x === undefined) {
    return 0;
  } else if (xs === undefined) {
    return 1;
  } else {
    return 1 + count(xs);
  }
}

使用ex-patterns,您可以按如下方式编写您的示例。您需要使用包附带的占位符名称(_ABC、... Z)但您可以重命名具有解构的回调函数中的匹配变量(包含所有命名匹配项的对象作为第一个参数传递给回调函数)。

import { when, then, Y, _, tail, end } from 'ex-patterns';

const count = list => (
    when(list)
        ([], then(() => 0))  // match empty array   
        ([_], then(() => 1))  // match array with (any) 1 element      
        ([_, tail(Y)], then(({ Y: xs }) => 1 + count(xs)))  // match array and capture tail              
    (end);
);

这也涵盖了 list = [undefined, 'foo', 'bar'] 的情况,我认为接受的答案不会涵盖这种情况。

为了提高代码效率,您可以使用 Immutable.js List 而不是数组来调用 count(无需更改)。在这种情况下,不需要在每个循环中将数组的 tail 部分切片并复制到新数组中。

与您提到的包一样,浏览器本身不会 运行,但我想这不是现代捆绑工具的主要障碍。

这是文档:https://moritzploss.github.io/ex-patterns/

免责声明:我是 ex-patterns 的作者 :)

我需要模式匹配并做了一些适合我的东西。

const count = patroon(
  [_], ([, ...xs]) => 1 + count(xs),
  [], 0
)

count([0,1,2,3])
4

有关更多用法示例,请参阅自述文件。