Loading...
墨滴

逸之

2022/01/05  阅读:31  主题:红绯

js vs sml

JavaScript à la ML 机器学习的 JavaScript

I just finished reading An Introduction to Functional Programming Through Lambda Calculus byGreg Michaelson. Towards the end, the author teaches some SML and Lisp. I came across a handful of short functions that took advantage of SML’s structure pattern matching syntax and recursion, two very important functional features which you may also see in more broadly used FP languages like Erlang, Haskell, Rust, F#, to name a few. I thought, why not JavaScript? While JavaScript has no native pattern matching support, there’ve been some valiant attempts to do so via userland libraries such as:

[

z: native pattern matching for javascript

GitHub is where people build software. More than 26 million people use GitHub to discover, fork, and contribute to over…

github.com

](https://github.com/z-pattern-matching)

However, I didn’t think they really brought much value. Other projects seemed really stale. The best would be, of course, to bring pattern matching natively to JavaScript as outlined in the following proposal:

然而,我并不认为它们真的带来了多少价值。其他项目看起来真的过时了。当然,最好的办法就是像下面的提议中所概述的那样,将模式匹配/代码本地化到 JavaScript 中去:

[

tc39/proposal-pattern-matching

proposal-pattern-matching - Pattern matching syntax for ECMAScript建议-模式匹配-ECMAScript 的模式匹配语法

github.com

网址: github. com

](https://github.com/tc39/proposal-pattern-matching)

[ https://github.com/tc39/proposal-pattern-matching ]

I urge you to support this stage-0 project as it definitely gets the conversation going and the attention it deserves. Nevertheless, JavaScript has come a long way with destructuring support, which you can think as a very elementary pattern match and a good starting point for this new proposal.

我敦促你支持这个阶段-0项目,因为它肯定得到了对话和应有的关注。尽管如此,JavaScript 已经在解构支持方面取得了长足的进步,你可以把它看作是一个非常基本的模式匹配,也是这个新提议的一个很好的起点。

So, I decided to use JavaScript to see if I could mimic the expressiveness in SML to approach some trivial functions in this functional manner.

因此,我决定使用 JavaScript,看看是否可以模仿 SML 中的表达能力,以这种函数式的方式处理一些琐碎的函数。

First, a little about the SML syntax you’ll see, if you’re not familiar. SML is a statically typed language, so an integer i is declared as i: int, a list of strings t as t: string list. Lastly, the infix :: concatenation operator that will return a new list with the first object in head position and the other in tail position, e.g. 0::[1,2,3] -> [0,1,2,3] . For the exercises posted here, this is the extent to which you ’ll use SML syntax.

首先,如果您不熟悉 SML 语法,那么您将看到一些有关 SML 语法的内容。SML 是一种静态类型的语言,因此整数 i 被声明为 i: int,字符串 t 的列表为 t: string 列表。最后,中缀: : concatenation 操作符将返回一个新列表,其中第一个对象位于头部位置,另一个对象位于尾部位置,例如0: : [1,2,3]-> [0,1,2,3]。对于这里发布的练习,这是您将使用 SML 语法的程度。

I’ll need to find JavaScript counterparts to these language features. Like I said before, destructuring allows me to easily decompose an array into head and tail using [h, … tail]as a substitute for [h::t]. This will make recursive solutions much easier. As far as types is concerned, I used Flow. With Flow, a number i is declared as i: number and a sequence of strings t as t: Array<string>. To get closer to SML, I’ll declare a Flow type alias:

我需要找到与这些语言特性相对应的 JavaScript。正如我之前所说的,destructuring 允许我使用[ h,... tail ]作为[ h: : t ]的替代品,轻松地将数组分解为 head 和 tail。这将使递归解决方案更加容易。就类型而言,我使用了 Flow。在 Flow 中,数字 i 被声明为 i: number,字符串序列 t 被声明为 t: Array < string > 。为了更接近 SML,我将声明一个 Flow 类型别名:

type list
   = Array
  
 

And that’s about it, really! Let’s work our way there:

就是这样,真的! 让我们按我们的方式来:

Example 1: functions of two case clauses例1: 两个格子句的功能

These examples showcase simple recursive algorithms with a two case-style pattern match: a base and a recursive step. Keep in mind, under the hood, pattern matching is nothing more than the top-bottom conditional branching matching the structure and shape of the provided arguments. When a match is found, the function executes the expression on the right. In SML, this would look like:

这些例子展示了简单的递归算法,其中包含两种大小写样式的模式匹配: 一个基本步骤和一个递归步骤。请记住,在引擎盖下面,模式匹配分支只不过是匹配所提供参数的结构和形状的顶部底部条件分支。当找到匹配项时,函数执行右边的表达式。在 SML 中,这看起来像:

fun length [] = 0 |  
    length (_::(t:int list)) = 1 + (length t);

There are 2 case style expressions. If you call length with an empty array, zero is returned. Otherwise, check the next case clause (separated by |) which would match a non-empty array. In this case, the head is matched with a wildcard character _ and discarded, finally the recursive call computes 1 plus the length of the tail of the list.

有两个大小写样式表达式。如果使用空数组调用 length,则返回零。否则,检查下一个 case 子句(由 | 分隔) ,它将匹配非空数组。在这种情况下,头部与通配符匹配,然后丢弃,最后递归调用计算1加上列表尾部的长度。

Now, pretend there’s no Array.prototype.length property in JavaScript for a moment, we could express this as:

现在,假设 JavaScript 中没有 Array.prototype.length 属性,我们可以这样表达:

const length = ([h, ...tail]: list
  ): number =>  
   isNil(h) ? 0  
            : 1 + length(tail)assert.equal(length([]), 0)  
assert.equal(length([1,2,3]), 3)
 

Structurally, I feel this function retains that same expressiveness of the pattern match clause on the left with the return value on the right. Think of each ternary operator a ? b : c as piping together the case clauses — match a, if true execute b, otherwise execute c. Aside from readability, I especially like that it pushes us to use tail recursion and immutability!

从结构上讲,我觉得这个函数保留了左侧模式匹配子句的表达能力,右侧的返回值也是如此。想想每个三元运算符 a?C 将 case 子句连接在一起ー匹配 a,如果为真,则执行 b,否则执行 c。除了可读性之外,我特别喜欢它推动我们使用尾递归和不变性!

In the same vein, we can create other little programs with the same pattern:

同样,我们也可以创建其他具有相同模式的小程序:

Sum elements in a list:

列表中的 Sum 元素:

const sum = ([h, ...tail]: list
  ): number =>  
  isNil(h) ? 0  
           : h + sum(tail)assert.equal(sum([]), 0)  
assert.equal(sum([1,2,3]), 6)
 

Print the first n cubes starting at 0:

从0开始打印第一个 n 个立方体:

const cubes = (n: number): list
   =>  
  !n ? [0]  
     : cubes(n - 1).concat([n * n * n])assert.deepEqual(cubes(0), [0])  
assert.deepEqual(cubes(3), [0, 1, 8, 27])
 

So, that’s all fun and good, but does this pattern break with > 2 case clauses?

所以,这些都是有趣和好的,但是这个模式是否打破了 > 2格子句?

Example 2: functions of three case clauses例二: 三个格子句的功能

I’ll implement a function that finds the ith element in string list. In SML:

我将实现一个在字符串列表中找到第 i 个元素的函数:

fun sifind _ [] = "can't find it" |  
    sifind 0 ((h:string)::_) = h  |  
    sifind (i:int) (_::(t:string list)) = sifind (i - 1) t;

This is the beauty and power of pattern matching in that it’s so declarative that you can read the algorithm off the screen: try to find any position in an empty list and get an error; or try to find the first string in the list then you get the head of the list; lastly, continue to look in the rest of the list.

这就是模式匹配的魅力所在,它是如此的宣示性,以至于你可以从屏幕上读出算法: 尝试在一个空列表中找到任何位置并得到一个错误; 或者尝试在列表中找到第一个字符串,然后得到列表的头部; 最后,继续查看列表的其余部分。

Let’s implement this in JavaScript so that it reads the same way. I’ve taken the liberty to add a bit more flare and declare a function find that would find the ith element in a list of objects mixed. The return type is an Either to better represent both the failure and the success states.

让我们在 JavaScript 中实现它,这样它就可以以同样的方式读取。我冒昧地添加了一些耀斑,并声明了一个函数 find,它可以在一个混合的对象列表中找到第 i 个元素。返回类型为 Either,以更好地表示失败和成功状态。

const find = (i: number, [h, ...tail]: list
  ): Either
  
      
   =>  
      isNil(h) ? Either.Left(`Element not found at ${i}`)  
     : i === 0 ? Either.Right(h)  
               : find(i - 1, tail)assert.isTrue(find(0, []).isLeft)  
assert.isTrue(find(1, [0]).isLeft)  
assert.isTrue(find(2, ['a', 'b', 'c']).isRight)    assert.equal(find(2, ['a', 'b', 'c']).fold(null, identity), 'c')
  
 

Let’s add another 3-case clause example. This time, I’ll write a function to replace the ith element of a list with another element. You should start to see a pattern in these:

让我们添加另一个3-case 子句示例。这一次,我将编写一个函数,用另一个元素替换列表中的第 i 个元素。你应该开始在下面这些中看到一个模式:

const replace = (i: number, e: mixed, [h, ...tail]: list
  ):     
list
  
      
  =>  
     isNil(h) ? []  
    : i === 0 ? [e, ...tail]  
    : [h].concat(replace(i - 1, e, tail))  
assert.deepEqual(replace(2, 'Jo',  
      ['Chris', 'Jean', 'Les', 'Pat', 'Phil']),  
      ['Chris', 'Jean', 'Jo', 'Pat', 'Phil']  
)
  
 

Hopefully, you’ve noticed another functional quality if all of these programs — immutability. In this particular case, replacing a value never changes the original array.

希望您已经注意到了所有这些程序的另一个函数性质ーー不可变性。在这种特殊情况下,替换值永远不会改变原始数组。

Let’s look at one last example, a general purpose list insertion function:

让我们看看最后一个例子,一个通用列表插入函数:

const insert = (e: any, [h, ...tail]: list
  ): list
  
    =>  
   isNil(h) ? [e]  
    : e < h ? [e, h, ...tail]  
            : [h].concat(insert(e, tail))assert.deepEqual(insert('Jo',  
      ['Chris', 'Jean', 'Les', 'Pat', 'Phil']),  
      ['Chris', 'Jean', 'Jo', 'Les', 'Pat', 'Phil']  
    )  
assert.deepEqual(insert('Jo', []), ['Jo'])
  
 

In this case I decided to use a list of any so that the overloaded comparison operator e < h works , just as in untyped JS.

在这种情况下,我决定使用 any 的列表,以便重载的比较运算符 e < h 能够工作,就像在非类型化的 JS 中一样。

Of course, I’d much rather see a more declarative pattern matching syntax rather than having to use if then else, but if you think about it, behind the scenes that’s kind of how it works.

当然,我更愿意看到一个更加声明性的模式匹配/语法,而不是必须使用 if then else,但是如果你仔细想想,在幕后这就是它的工作原理。

That’s all I wanted to share. I thought it was really great that we can reason about and express code in this way using JavaScript. It’s a testament to how malleable the language is. I think it’s definitely headed in the right direction and we should continue pushing for these FP-oriented proposals as much as possible.

这就是我想要分享的。我认为我们能够通过 JavaScript 来推理和表达代码,这真的很棒。这证明了语言的可塑性。我认为它的方向肯定是正确的,我们应该继续推动这些面向粮食计划署的建议尽可能多。

Thanks for reading!

谢谢阅读!

P.S. If you have an example of a > 3 case “pattern matching” function in JS, please feel free to drop a comment :-)

附:。如果你在 JS 中有一个大于3个大小写的“模式匹配”函数的例子,请随时删除注释: -)

Resources 资源

  • An Introduction to Functional Programming Through Lambda Calculus, Greg Michaelson
    通过 Lambda 演算介绍函数式编程

[

Luis Atencio 路易斯 · 阿滕西奥

](/@luijar?source=post_sidebar--------------------------post_sidebar--------------)

[/@luijar? source = post _ sidebar ———————— -- post _ sidebar —————————————————————————————————————————————————————————————— --)

Author of Functional Programming in JavaScript (Manning 2016) an intro in FP, RxJS in Action (Manning 2017), Functional PHP (Leanpub)

函数式编程在 JavaScript (Manning 2016)的作者介绍在 FP,RxJS 在行动(Manning 2017) ,函数式 PHP (Leanpub)

FollowLuis Atencio Follows

以下是路易斯 · 阿滕西奥的照片

  • Eric Elliott[

    Eric Elliott 埃里克 · 埃利奥特

    ](/@_ericelliott?source=blogrolls_sidebar-----faa2911b65f-----------------------------------)

    [/@_ ericelliott? source = blogrolls _ sidebar---faa2911b65f---------------------------------------------------------------------------------------------------------------------------------------- -

  • John Rampton[

    John Rampton 约翰 · 兰普顿

    ](/@johnrampton?source=blogrolls_sidebar-----faa2911b65f-----------------------------------)

    [](//@johnrampton? source = blogrolls _ sidebar---fa2911b65f------------------------------------------------------------------------------------------------------------------------

  • Thoughtworks[

    Thoughtworks

    ](https://thoughtworks.medium.com/?source=blogrolls_sidebar-----faa2911b65f-----------------------------------)

    [ https://thoughtworks.medium.com/?source=blogrolls_sidebar-----faa2911b65f----------------------------------- ]

  • Medium[

    Medium 中等

    ](/@Medium?source=blogrolls_sidebar-----faa2911b65f-----------------------------------)

    [](/@medium? source = blogrolls _ sidebar---faa2911b65f---------------------------------------------------------------------------------------------------------------------------------- -

  • Rebeca Montaner[

    Rebeca Montaner 丽贝卡 · 蒙塔纳

    ](/@rebecamontaner?source=blogrolls_sidebar-----faa2911b65f-----------------------------------)

    [//@rebecamontaner? source = blogrolls _ sidebar ---faa2911b65f ———————————————————————————————————————————————————————————————————————————————— --)

See all (107)

参见全文(107)

40

2

图2

40 claps

40次掌声

40

2

图2

More from Luis Atencio 更多来自 Luis Atencio

Follow

跟着

Author of Functional Programming in JavaScript (Manning 2016) an intro in FP, RxJS in Action (Manning 2017), Functional PHP (Leanpub)

函数式编程在 JavaScript (Manning 2016)的作者介绍在 FP,RxJS 在行动(Manning 2017) ,函数式 PHP (Leanpub)

[

Aug 25, 2017

2017年8月25日

](/@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc?source=follow_footer-----faa2911b65f----0-------------------------------)

[](//@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc? source = follow _ footer-- fa2911b65f-- 0---------------------------------------------------------------------------------------------------- -

Mixin Monoidal behavior in JavaScript JavaScript 中的 Mixin Monoidal 行为

[![](https://miro.medium.com/max/1400/1*uY7ex6hCw7attrPtBhB_Mg.jpeg)](https://medium.com/@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc?source=follow_footer-----faa2911b65f----0-------------------------------)
( https://miro.medium.com/max/1400/1*uy7ex6hcw7attrptbhb_mg.jpeg )( https://medium.com/@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc?source=follow_footer-----faa2911b65f----0------------------------------- )

Like these ninjas, the term monoid is a bit aggressive and intimidating. In practice, though, it’s a actually a very simple concept with very powerful applications not only in mathematics, but in application code and programming language design. To begin, let’s define another stealthy concept — a Semigroup.

就像这些忍者一样,monoid 这个词有点咄咄逼人。实际上,这是一个非常简单的概念,不仅在数学上,而且在应用程序代码和编程语言设计中都有非常强大的应用。首先,让我们定义另一个隐秘的概念ーー半群。

Semigroup 半群

Semigroups are…

半群是..。

[

Read more · 10 min read

多读10分钟

](/@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc?readmore=1&source=follow_footer-----faa2911b65f----0-------------------------------)

[//@luijar/mixin-monoidal-behavior-in-javascript-4e5c4dcb3ffc? readmore = 1 & source = follow _ footer---fa2911b65f-- 0----------------------------------------------------------------------------------------------------------

75


Share your ideas with millions of readers.

与数以百万计的读者分享你的想法。

Write on Medium

在媒介上写作


[

Aug 9, 2017

2017年8月9日

](/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4?source=follow_footer-----faa2911b65f----1-------------------------------)

[](//@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4? source = follow _ footer---fa2911b65f-- 1-------------------------------------------------------------------------------------------- -

Kleisli Compositions in JavaScript 在 JavaScript 中的 Kleisli 组合

[![](https://miro.medium.com/max/1400/1*VdSkSS31HKmgKYuF-40AMg.png)](https://medium.com/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4?source=follow_footer-----faa2911b65f----1-------------------------------)
( https://miro.medium.com/max/1400/1*vdskss31hkmgkyuf-40amg.png )( https://medium.com/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4?source=follow_footer-----faa2911b65f----1------------------------------- )

You’ve probably read many times that the goal of functional programs is to achieve a state where you can compose only pure or side effect-free functions. One day, you sit at your computer at work determined to begin crafting your functions to meet this requirement. It’s all looking good, your…

您可能已经多次阅读过函数式程序的目标是实现只能编写纯函数或无副作用函数的状态。有一天,你坐在电脑前工作,下定决心开始精心设计你的功能来满足这个要求。一切看起来都很好你的..。

[

Read more · 7 min read

阅读更多7分钟

](/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4?readmore=1&source=follow_footer-----faa2911b65f----1-------------------------------)

[/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4? readmore = 1 & source = follow _ footer ---faa2911b65f -- 1—————————————— -- -)

653

[

8

图8

](/@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4?responsesOpen=true&source=follow_footer-----faa2911b65f----1-------------------------------)

](//@luijar/kliesli-compositions-in-javascript-7e1a7218f0c4? responsesOpen = true & source = follow _ footer---faa2911b65f-- 1--------------------------------------------------------------------------------------------------


[

Aug 25, 2016

2016年8月25日

](/@luijar/the-observable-disguised-as-an-io-monad-c89042aa8f31?source=follow_footer-----faa2911b65f----2-------------------------------)

[//@luijar/the-observable-discreated-as-an-io-monad-c89042aa8f31? source = follow _ footer---- fa2911b65f-- 2---------------------------------------------------------------------------------------------- -

The Observable disguised as an IO Monad被观察者伪装成 i/o 单子

[![](https://miro.medium.com/max/1400/1*KIsxQd-7az_tgONMKa-xSA.png)](https://medium.com/@luijar/the-observable-disguised-as-an-io-monad-c89042aa8f31?source=follow_footer-----faa2911b65f----2-------------------------------)
( https://miro.medium.com/max/1400/1*kisxqd-7az_tgonmka-xsa.png )( https://medium.com/@luijar/the-observable-disguised-as-an-io-monad-c89042aa8f31?source=follow_footer-----faa2911b65f----2------------------------------- )

So, before we talk about IO and Observable monads, I’ll briefly explain what monads are. …

因此,在我们讨论 i/o 和观察到的单子之前,我将简要地解释什么是单子。 ..。

[

Read more · 7 min read

阅读更多7分钟

](/@luijar/the-observable-disguised-as-an-io-monad-c89042aa8f31?readmore=1&source=follow_footer-----faa2911b65f----2-------------------------------)

[//@luijar/the-observable-discreated-as-an-io-monad-c89042aa8f31? readmore = 1 & source = follow _ footer---faa2911b65f-- 2-------------------------------------------------------------------------------------------------- -

437

[

3

图3

](/@luijar/the-observable-disguised-as-an-io-monad-c89042aa8f31?responsesOpen=true&source=follow_footer-----faa2911b65f----2-------------------------------)

[//@luijar/the-observable-discreated-as-an-io-monad-c89042aa8f31? responsesOpen = true & source = follow _ footer---fa2911b65f-- 2----------------------------------------------------------------------------------------------------


[

May 26, 2016

2016年5月26日

](/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f?source=follow_footer-----faa2911b65f----3-------------------------------)

](//@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f? source = follow _ footer ——-fa2911b65f ——3—————————————— -)

RxJS5 + PouchDB — persistent data flows RxJS5 + PouchDB ー持久数据流

[![](https://miro.medium.com/max/1392/1*bdoukIhEMtXReMUH3RrUUw.jpeg)](https://medium.com/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f?source=follow_footer-----faa2911b65f----3-------------------------------)
( https://miro.medium.com/max/1392/1*bdoukihemtxremuh3rruuw.jpeg )( https://medium.com/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f?source=follow_footer-----faa2911b65f----3------------------------------- )

In this new post, I plan to mix two fundamentally different ways of looking at data flows: static vs dynamic. We can think of static data as one that is durable or survives permanently; in contrast, dynamic data is always in flux and moving through the system — it’s transient…

在这篇新的文章中,我计划混合两种根本不同的方式来看待数据流: 静态的和动态的。我们可以认为静态数据是持久的或永久存在的; 相比之下,动态数据总是处于流动状态,并在系统中移动ーー它是暂时的... ..。

[

Read more · 11 min read

阅读11分钟阅读

](/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f?readmore=1&source=follow_footer-----faa2911b65f----3-------------------------------)

](/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f? readmore = 1 & source = follow _ footer-- fa2911b65f-- 3---------------------------------------------------------------------------------------------------- -

126

[

3

图3

](/@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f?responsesOpen=true&source=follow_footer-----faa2911b65f----3-------------------------------)

](//@luijar/rxjs-pouchdb-persistent-data-flows-480f503ee41f? responsesOpen = true & source = follow _ footer-- fa2911b65f-- 3---------------------------------------------------------------------------------------------------- -


[

Dec 23, 2015

2015年12月23日

](/@luijar/understanding-lambda-expressions-4fb7ed216bc5?source=follow_footer-----faa2911b65f----4-------------------------------)

[//@luijar/understanding-lambda-expressions-4fb7ed216bc5? source = follow _ footer---faa2911b65f-- 4---------------------------------------------------------------------------------------- -

[![](https://miro.medium.com/max/1200/1*sNTeyszX-eLPjqDAwB9yuQ.png)](https://medium.com/@luijar/understanding-lambda-expressions-4fb7ed216bc5?source=follow_footer-----faa2911b65f----4-------------------------------)
( https://miro.medium.com/max/1200/1*snteyszx-elpjqdawb9yuq.png )( https://medium.com/@luijar/understanding-lambda-expressions-4fb7ed216bc5?source=follow_footer-----faa2911b65f----4------------------------------- )

Understanding Lambda Expressions 理解 Lambda 表达式

Lambda expressions (or lambda functions) are essentially blocks of code that can be assigned to variables, passed as an argument, or returned from a function call, in languages that support high-order functions. They have been part of programming languages for quite some time. Some examples include Smalltalk, Lisp, Ruby, Scala…

Lambda 表达式(或 Lambda 函数)实质上是一些代码块,可以用支持高阶函数的语言分配给变量、作为参数传递或从函数调用返回。它们作为编程语言的一部分已经有相当长的时间了。比如 Smalltalk,Lisp,Ruby,Scala..。

[

Read more · 5 min read

多读5分钟

](/@luijar/understanding-lambda-expressions-4fb7ed216bc5?readmore=1&source=follow_footer-----faa2911b65f----4-------------------------------)

[//@luijar/understanding-lambda-expressions-4fb7ed216bc5? readmore = 1 & source = follow _ footer-- fa2911b65f-- 4---------------------------------------------------------------------------------------------- -

320

[

2

图2

](/@luijar/understanding-lambda-expressions-4fb7ed216bc5?responsesOpen=true&source=follow_footer-----faa2911b65f----4-------------------------------)

[//@luijar/understanding-lambda-expressions-4fb7ed216bc5? responsesOpen = true & source = follow _ footer-- fa2911b65f-- 4----------------------------------------------------------------------------------------------------------------


More From Medium 更多来自 Medium

Publish NPM package on a Gitlab instance在 Gitlab 实例上发布 NPM 包

Arman Safikhani

Vue + Element 元素

Leo

狮子座

3 Language Constructs From Dart That You Are Missing Out on in JavaScript3种你在 JavaScript 中错过的 Dart 语言结构

Ali Nasserzadeh in Better Programming

How to Pass Commit Hash to an Environment Variable Using Webpack Plugin in Vue 3

Dawid Witulski in JavaScript in Plain English

React Form Libraries: Redux Form, Formik and React Hook Form

Yusuf Eren Ayas

Typescript Accesor: Beautiful Getters and Setters

Janith Kasun

How to build a News App with React Native (Part 2) (Home Module)

Moses Esan in Mesan Digital

This is a test

Alejo Rivera

About

Write

Help

Legal

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App storeA button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store ×拖拽到此处图片将完成下载

逸之

2022/01/05  阅读:31  主题:红绯

作者介绍

逸之