Elm语言:修订间差异
小 →特征 |
小 GZWDer移动页面Elm (编程语言)至Elm语言 |
||
(未显示5个用户的43个中间版本) | |||
第1行: | 第1行: | ||
{{NoteTA|G1=IT}} |
|||
{{Infobox programming language |
{{Infobox programming language |
||
| name = Elm |
| name = Elm |
||
| logo = [[File:Elm logo.svg|120px|The Elm tangram]] |
| logo = [[File:Elm logo.svg|120px|The Elm tangram]] |
||
| paradigm = [[函数式编程|函数式]] |
| paradigm = [[函数式编程|函数式]] |
||
| released = {{Start date and age|2012|3|30}}<ref name="initialrelease">{{cite web|url=https://www.reddit.com/r/haskell/comments/rkyoa/my_thesis_is_finally_complete_elm_concurrent_frp/|last1=Czaplicki|first1=Evan|title=My Thesis is Finally Complete! "Elm: Concurrent FRP for functional GUIs"|website=Reddit}}</ref> |
| released = {{Start date and age|2012|3|30}}<ref name="initialrelease">{{cite web|url=https://www.reddit.com/r/haskell/comments/rkyoa/my_thesis_is_finally_complete_elm_concurrent_frp/|last1=Czaplicki|first1=Evan|title=My Thesis is Finally Complete! "Elm: Concurrent FRP for functional GUIs"|website=Reddit|access-date=2021-02-27|archive-date=2021-04-13|archive-url=https://web.archive.org/web/20210413104532/https://www.reddit.com/r/haskell/comments/rkyoa/my_thesis_is_finally_complete_elm_concurrent_frp/}}</ref> |
||
| latest release version = 0.19.1 |
| latest release version = 0.19.1 |
||
| latest release date = {{Start date and age|2019|10|21}}<ref>https://github.com/elm/compiler/releases</ref> |
| latest release date = {{Start date and age|2019|10|21}}<ref>{{Cite web |url=https://github.com/elm/compiler/releases |title=存档副本 |access-date=2021-02-27 |archive-date=2020-12-18 |archive-url=https://web.archive.org/web/20201218155858/https://github.com/elm/compiler/releases/ }}</ref> |
||
| influenced_by = [[Haskell]], [[Standard ML]], [[OCaml]], [[F♯|F#]] |
| influenced_by = [[Haskell]], [[Standard ML]], [[OCaml]], [[F♯|F#]] |
||
| influenced = [[Redux (JavaScript函式库)|Redux]],<ref>{{cite web|url=https://redux.js.org/introduction/prior-art|title=Prior Art - Redux|website=redux.js.org}}</ref> [[Vue.js|Vuex]]<ref>{{cite web|url=https://vuejs.org/v2/guide/comparison.html#Scale|title=Comparison with Other Frameworks — Vue.js}}</ref> |
| influenced = [[Redux (JavaScript函式库)|Redux]],<ref>{{cite web|url=https://redux.js.org/introduction/prior-art|title=Prior Art - Redux|website=redux.js.org|access-date=2021-02-27|archive-date=2020-09-21|archive-url=https://web.archive.org/web/20200921002110/https://redux.js.org/introduction/prior-art/}}</ref> [[Vue.js#核心插件|Vuex]]<ref>{{cite web|url=https://vuejs.org/v2/guide/comparison.html#Scale|title=Comparison with Other Frameworks — Vue.js|access-date=2021-02-27|archive-date=2021-05-03|archive-url=https://web.archive.org/web/20210503172856/https://vuejs.org/v2/guide/comparison.html#Scale}}</ref> |
||
| typing = [[静态类型|静态]], [[强类型]], [[类型推论]] |
| typing = [[静态类型|静态]], [[强类型]], [[类型推论]] |
||
| designer = Evan Czaplicki |
| designer = Evan Czaplicki |
||
| website = {{Official URL}} |
| website = {{Official URL}} |
||
| license = [[寬鬆自由軟體授權條款|宽松 |
| license = [[寬鬆自由軟體授權條款|宽松许可证]] ([[BSD许可证|三条款BSD许可证]])<ref name=license>{{cite web|url=https://github.com/elm/compiler/blob/master/LICENSE|title=elm/compiler|website=GitHub|access-date=2021-02-27|archive-date=2019-03-21|archive-url=https://web.archive.org/web/20190321211907/https://github.com/elm/compiler/blob/master/LICENSE}}</ref> |
||
| file_ext = .elm |
| file_ext = .elm |
||
}} |
}} |
||
'''Elm'''是一个[[领域特定语言|领域特定]][[编程语言]],用于[[声明式编程|声明式]] |
'''Elm'''是一个[[领域特定语言|领域特定]][[编程语言]],用于[[声明式编程|声明式]]地创建基于[[web浏览器]]的[[图形用户界面]]。Elm是[[纯函数式编程|纯函数式]]的,开发它时强调了[[易用性]]、性能和[[健壮性 (计算机科学)|健壮性]]。它宣传为“实际上没有[[执行期|运行时间]][[异常处理|异常]]”<ref>{{cite web|url=https://elm-lang.org/|title=Elm home page|access-date=2021-02-27|archive-date=2021-05-07|archive-url=https://web.archive.org/web/20210507051114/https://elm-lang.org/}}</ref>,Elm编译器的[[类型系统|静态类型检查]]使之成为可能。 |
||
==历史 == |
==历史 == |
||
Elm最初由Evan Czaplicki作为论文于 |
Elm最初由Evan Czaplicki在2012年作为毕业论文《Elm:用于函数式GUI的并发[[函数式响应式编程|FRP]]》而设计的<ref>{{cite web | first = Evan | last = Czaplicki | url = https://elm-lang.org/assets/papers/concurrent-frp.pdf | title = Elm: Concurrent FRP for Functional GUIs | access-date = 2021-02-27 | archive-date = 2021-04-16 | archive-url = https://web.archive.org/web/20210416070805/https://elm-lang.org/assets/papers/concurrent-frp.pdf }}<br />{{cite web|url=https://csmith111.gitbooks.io/functional-reactive-programming-with-elm/content/section5/Signals.html|title=Programming with Elm-Signals|author=csmith111}}<br />{{cite web |last1=Czaplicki |first1=Evan |title=A Farewell to FRP |url=http://elm-lang.org/blog/farewell-to-frp |quote=When I started working on my thesis in 2011, I stumbled upon this academic subfield called Functional Reactive Programming (FRP). By stripping that approach down to its simplest form, I ended up with something way easier to learn than similar functional languages. Signals meant piles of difficult concepts just were not necessary in Elm. ……<br />As The Elm Architecture emerged, it became clear that you could do almost all your Elm programming without thinking about signals at all. ……<br />In the end, it was possible to remove signals because Elm has been moving towards an explicit emphasis on concurrency for quite some time now. ……Just like with my thesis, Concurrent FRP, the goal is to get the benefits of concurrency for free. ……<br />Note: Interested readers may find [https://www.di.ens.fr/~pouzet/lucid-synchrone/index.html Lucid Synchrone] interesting. Unfortunately for me, I had no idea my thesis had so much in common with [[同步式编程|synchronous programming]] languages at the time, but the connections are quite striking. I might argue that Elm was never about FRP. |website=elm |access-date=14 July 2018 |ref=farewell-to-frp |archive-date=2019-05-31 |archive-url=https://web.archive.org/web/20190531181806/https://elm-lang.org/blog/farewell-to-frp }}</ref>。Elm的首次发行带有很多例子和一个在线编辑器,使得易于在[[web浏览器]]中试验它<ref>{{cite web|url=https://elm-lang.org/try|title=Try Elm|website=elm-lang.org|access-date=2019-07-24|archive-url=https://web.archive.org/web/20170521144831/http://elm-lang.org/try|archive-date=2017-05-21}}</ref>。Evan在2013年加入[[Prezi]]从事Elm的工作<ref>{{cite web|url=https://elm-lang.org/news/elm-and-prezi|title=elm and prezi|website=elm-lang.org|access-date=2021-02-27|archive-date=2021-04-17|archive-url=https://web.archive.org/web/20210417114025/https://elm-lang.org/news/elm-and-prezi}}</ref>,并在2016年转移到{{en-link|NoRedInk}}作为开源工程师,启动了Elm软件基金会<ref>{{cite web|url=https://elm-lang.org/news/new-adventures-for-elm|title=new adventures for elm|website=elm-lang.org|access-date=2021-02-27|archive-date=2021-04-17|archive-url=https://web.archive.org/web/20210417143931/https://elm-lang.org/news/new-adventures-for-elm}}</ref>。 |
||
Elm编译器的最初实现 |
Elm编译器的最初实现执行目标为[[HTML]]、[[层叠样式表|CSS]]和[[JavaScript]]<ref>{{cite web|url=https://github.com/elm/compiler|title=elm/compiler|website=GitHub|access-date=2021-02-27|archive-date=2021-04-14|archive-url=https://web.archive.org/web/20210414225230/https://github.com/elm/compiler}}</ref>。核心工具集持续的扩展,现在包括了[[读取﹣求值﹣输出循环|REPL]]<ref>{{cite web|url=https://elm-lang.org/news/repl|title=repl|website=elm-lang.org|access-date=2021-02-27|archive-date=2019-11-27|archive-url=https://web.archive.org/web/20191127051844/https://elm-lang.org/news/repl}}</ref>、[[软件包管理系统|包管理器]]<ref>{{cite web|url=https://elm-lang.org/news/package-manager|title=package manager|website=elm-lang.org|access-date=2021-02-27|archive-date=2020-09-18|archive-url=https://web.archive.org/web/20200918203416/https://elm-lang.org/news/package-manager}}</ref>、时间旅行调试器<ref>{{cite web|url=https://elm-lang.org/news/time-travel-made-easy|title=Home|website=elm-lang.org|access-date=2021-02-27|archive-date=2020-12-03|archive-url=https://web.archive.org/web/20201203095515/https://elm-lang.org/news/time-travel-made-easy}}</ref>和针对macOS及Windows的安装器<ref>{{cite web|url=https://guide.elm-lang.org/install.html|title=Install|website=guide.elm-lang.org|access-date=2021-02-27|archive-date=2019-07-24|archive-url=https://web.archive.org/web/20190724070357/https://guide.elm-lang.org/install.html}}</ref>。 Elm还有一个生态系统,包括社区创建的库<ref>{{Cite web |url=https://package.elm-lang.org/packages/ |title=community created libraries |access-date=2021-02-27 |archive-date=2015-02-11 |archive-url=https://web.archive.org/web/20150211183935/http://package.elm-lang.org/packages/ }}</ref>和Ellie<ref>{{Cite web |url=https://ellie-app.com/ |title=Ellie |access-date=2022-05-12 |archive-date=2021-01-22 |archive-url=https://web.archive.org/web/20210122223916/https://ellie-app.com/ }}</ref>,它是一个高级在线编辑器,允许保存工作和包含社区库。 |
||
== 特征 == |
== 特征 == |
||
Elm有一个小集合的语言构造,包括传统的if表达式,let表达式用于局部状态,和case表达式用于 |
Elm有一个小集合的语言构造,包括传统的if表达式,let表达式用于局部状态,和case表达式用于[[模式匹配]]<ref name="syntax">{{cite web|url=http://elm-lang.org/learn/Syntax.elm|title=syntax|website=elm-lang.org|access-date=2013-05-31|archive-url=https://web.archive.org/web/20160313052210/http://elm-lang.org/learn/syntax.elm|archive-date=2016-03-13}}</ref>。作为函数式语言,它缺省的支持[[匿名函数]],函数作为实际参数,和部份应用。它的语义包括不可变的值,[[纯函数|无状态函数]],和具有类型推论的静态类型。Elm程序通过虚拟的DOM呈现HTML,还可以使用“JavaScript作为服务”来与其他代码进行互操作。 |
||
=== 不可变性 === |
|||
在Elm中所有的值都是[[不可变对象|不可变]]的,这意味着一个值不能在创建之后修改。Elm使用[[持久性数据结构]]来实现它的<code>Array</code>、<code>Dict</code>和<code>Set</code>库<ref>{{cite web|url=https://package.elm-lang.org/packages/elm/core/latest/|title=elm/core|website=package.elm-lang.org|access-date=2021-02-28|archive-date=2021-04-17|archive-url=https://web.archive.org/web/20210417115301/https://package.elm-lang.org/packages/elm/core/latest/}}</ref>。 |
|||
=== 静态类型 === |
|||
Elm是静态类型的。类型标注(annotation)是可选的(由于有类型推论)但强烈鼓励。标注存在于定义之上的一行(不同于C家族语言,这里的类型和名字是夹杂在一起的)。Elm使用单一的冒号表达“拥有类型”。 |
|||
类型包括原始类型如整数和字符串,和基本数据结构比如列表、元组和记录。函数拥有用箭头写成的类型,例如<code>round : Float -> Int</code>。[[标签联合|定制类型]]允许编程者建立定制类型,以匹配特定问题领域的方式来表示数据<ref>{{cite web|title=Model The Problem|url=https://guide.elm-lang.org/types/custom_types.html|website=Elm|access-date=4 May 2016|ref=tagged-unions|archive-date=2020-11-11|archive-url=https://web.archive.org/web/20201111190215/https://guide.elm-lang.org/types/custom_types.html}}</ref>。 |
|||
类型可以推论出其他类型,例如<code>List Int</code>。类型总是首字母大写;小写名字是类型变量。例如,<code>List a</code>是未知类型的值的列表。它是空列表和给<code>List.length</code>的实际参数的类型,对于这个列表的元素而言它是不可知的。有一些特殊类型,编程者建立用来与Elm运行时进行交互。例如,<code>Html Msg</code>表示(虚拟)DOM树,其事件处理类型<code>Msg</code>的所有产生消息。 |
|||
不再允许任何值是隐含的可空值(比如JavaScript的<code>undefined</code>或[[空指针]]),Elm的标准库定义了<code>Maybe a</code>类型。产生或处理一个可选值的代码不显式的使用这个类型,而所有其他代码得到保证声称了类型的值是实际上存在的。 |
|||
Elm提供有限数目的内建[[类型类]]:<code>number</code>,它包括<code>Int</code>和<code>Float</code>,用来利用数值算符比如<code>(+)</code>或<code>(*)</code>;<code>comparable</code>,它包括数值、字符、字符串、可比较者的列表和可比较者的元组,用来利用比较算符;和<code>appendable</code>,它包括字符串和列表,用来利用<code>(++)</code>进行串接。Elm不提供将定制类型包括入这些类型类,或建立新类型类的机制(参见限制章节)。 |
|||
=== 模块系统 === |
|||
Elm拥有[[模块化编程|模块系统]]来允许用户将其代码分解到叫做模块的更小的部份之中。模块可以隐藏实现细节比如帮助函数,并组织有关的代码在一起。模块为可导入代码充当名字空间,比如<code>Bitwise.and</code>。第三方库(或包)构成自一个或多个模块,并可从Elm公共库中获得到<ref>{{Cite web |url=https://package.elm-lang.org/ |title=Elm Public Library |access-date=2021-02-27 |archive-date=2021-05-19 |archive-url=https://web.archive.org/web/20210519203859/https://package.elm-lang.org/ }}</ref>。所有的库都采用[[软件版本号|语义版本号]],这是编译器和其他工具所强制的。就是说,移除一个函数或改变它的类型只能在主要发行中进行。 |
|||
=== 同HTML、CSS和JavaScript的互操作 === |
|||
Elm使用叫做端口的抽象来与[[JavaScript]]通信<ref>{{cite web|url=https://guide.elm-lang.org/interop/|title=JavaScript interop|website=elm-lang.org|access-date=2021-02-28|archive-date=2021-05-21|archive-url=https://web.archive.org/web/20210521204323/https://guide.elm-lang.org/interop/}}</ref>。它允许值流入和流出Elm程序,确使了在Elm和JavaScript之间的通信。 |
|||
Elm有一个叫做elm/html的库,编程者可以用来在Elm内书写HTML和CSS<ref>{{cite web|url=https://package.elm-lang.org/packages/elm/html/latest/|title=elm/html|website=package.elm-lang.org|access-date=2021-02-28|archive-date=2021-05-11|archive-url=https://web.archive.org/web/20210511143618/https://package.elm-lang.org/packages/elm/html/latest/}}</ref>。它使用虚拟[[文档对象模型|DOM]]方式来使更新有效率<ref>{{cite web|url=https://elm-lang.org/news/blazing-fast-html|title=Blazing Fast HTML|website=elm-lang.org|access-date=2021-02-28|archive-date=2020-09-18|archive-url=https://web.archive.org/web/20200918194731/https://elm-lang.org/news/blazing-fast-html}}</ref>。 |
|||
=== 后端 === |
|||
Elm官方上不支持服务器端开发。核心开发团队不将它作为主要目标考虑,并且偏好聚焦于在增进前端开发体验上的开发。尽管如此,有一些独立的计划,它们尝试探索将Elm用于后端的可能性。这些计划主要系附于Elm版本0.18.0,因为更新的版本不支持“原生”代码和其他可利用特征。有两个尝试将Elm用在BEAM(Erlang虚拟机)之上。其中一个计划直接在这个环境上执行Elm<ref>{{Cite web |url=https://github.com/hkgumbs/elm-beam |title=存档副本 |access-date=2021-02-28 |archive-date=2020-09-08 |archive-url=https://web.archive.org/web/20200908074135/https://github.com/hkgumbs/elm-beam/ }}</ref>,而另一个计划把它编译成Elixir<ref>{{Cite web |url=https://github.com/wende/elchemy |title=存档副本 |access-date=2021-02-28 |archive-date=2021-01-04 |archive-url=https://web.archive.org/web/20210104022452/https://github.com/wende/elchemy }}</ref>。还有一个尝试通过Node.js下部结构为Elm建立后端框架<ref>{{Cite web |url=https://github.com/AIRTucha/board |title=存档副本 |access-date=2021-02-28 |archive-date=2020-11-22 |archive-url=https://web.archive.org/web/20201122145516/https://github.com/AIRTucha/board }}</ref>。这些计划都没有准备好用于生产。 |
|||
== Elm架构 == |
|||
Elm架构是建造交互式web应用的模式。Elm应用本质上以这种方式来构造,但是其他项目可能发现这个概念很有用。 |
|||
Elm程序总是分解成三个部份: |
|||
* 模型:这个应用的状态, |
|||
* 视图:一个把模型转变成HTML的函数, |
|||
* 更新:一个基于消息更新模型的函数。 |
|||
这些是Elm架构的核心。 |
|||
例如,想象显示一个数值和在按下时增加这个数值的一个按钮的一个应用<ref>{{Cite web|title=Buttons · An Introduction to Elm|url=https://guide.elm-lang.org/architecture/buttons.html|access-date=2020-10-15|website=guide.elm-lang.org|archive-date=2020-11-11|archive-url=https://web.archive.org/web/20201111225815/https://guide.elm-lang.org/architecture/buttons.html}}</ref>。在这种情况下,所有我们需要存储的是一个数值,所以我们的模型可以简单的就是<code>type alias Model = Int</code>。<code>view</code>函数将用<code>Html</code>库来定义并显示这个数值和按钮。为了让这个数值被更新,我们需要能够向<code>update</code>函数发送消息,这是通过定制类型比如<code>type Msg = Increase</code>来完成的。 <code>Increase</code>值被附着于在<code>view</code>函数内定义的按钮,使得在用户点击这个按钮的时候,<code>Increase</code>被传递到<code>update</code>函数之上,它可以通过增加这个数值来更新这个模型。 |
|||
在Elm架构中,发送消息至<code>update</code>是改变状态的唯一方式。在更加复杂的应用中,消息可以来自各种来源:用户交互,模型初始化,来自<code>update</code>的内部调用,订阅的外部事件(窗口改变大小、系统时钟、JavaScript互操作等等)和URL变更及请求。 |
|||
== 限制 == |
|||
Elm不支持[[类型类#高种类多态|高种类多态]]<ref>{{cite web|title=Higher-Kinded types Not Expressible? #396|url=https://github.com/elm-lang/elm-compiler/issues/396|website=github.com/elm-lang/elm-compiler|access-date=6 March 2015}}</ref>,这是同为函数式的语言[[Haskell]]和[[PureScript]]所提供的,Elm还不支持创建[[类型类]]。 |
|||
这意味着,例如Elm没有跨越多种数据结构如<code>List</code>和<code>Set</code>的通用的<code>map</code>函数。在Elm中,这种函数典型的要限定上它们的模块名字来调用,例如调用<code>List.map</code>和<code>Set.map</code>。在Haskell或PureScript中,只有一个函数<code>map</code>。自从2015年这就是在Czaplicki的粗略路线图上的一个周知的特征要求<ref>{{cite web|title=Higher-Kinded types Not Expressible #396|url=https://github.com/elm/compiler/issues/396#issuecomment-128190898|website=github.com/elm-lang/elm-compiler|access-date=19 November 2019|archive-date=2020-12-18|archive-url=https://web.archive.org/web/20201218152958/https://github.com/elm/compiler/issues/396#issuecomment-128190898}}</ref>。 |
|||
另一个缺陷是在中到大型项目中有大量的{{en-link|样板代码|Boilerplate code}},如《Elm in Action》作者在他们的单一页面应用例子中所展示的那样<ref>{{cite web|title=Main.elm|url=https://github.com/rtfeldman/elm-spa-example/blob/23dee34dd7a8c26229a03bc8e9f0e034f6222f13/src/Main.elm|website=github.com/rtfeldman/elm-spa-example|access-date=30 June 2020}}</ref>,具有几乎同样的片段被重复于更新、视图、订阅、路由解析和建造函数之中。 |
|||
== 样例代码 == |
== 样例代码 == |
||
第54行: | 第102行: | ||
sqrt (a^2 + b^2) |
sqrt (a^2 + b^2) |
||
-- 函数可以柯里化;这里我们柯里化 |
-- 函数可以柯里化;这里我们柯里化乘法中缀算符于数2之上。 |
||
-- 乘法中缀算符于一个2。 |
|||
multiplyBy2 : number -> number |
multiplyBy2 : number -> number |
||
multiplyBy2 = |
multiplyBy2 = |
||
第102行: | 第149行: | ||
== 参见 == |
== 参见 == |
||
* [[PureScript]]:一个强类型的、纯函数式的编译成JavaScript的编程语言。 |
* [[PureScript]]:一个强类型的、纯函数式的编译成JavaScript的编程语言。 |
||
* |
* [[Reason (编程语言)|Reason]]:[[OCaml]]的语法扩展和工具链,也可以转译成JavaScript。 |
||
* [[函数式响应式编程]] |
|||
== 引用 == |
== 引用 == |
||
第109行: | 第157行: | ||
== 外部链接 == |
== 外部链接 == |
||
* {{Official website}} |
* {{Official website}} |
||
* {{cite web|url=https://project-awesome.org/sporto/awesome-elm|title=Awesome Elm|access-date=2021-03-02|archive-date=2021-01-17|archive-url=https://web.archive.org/web/20210117020553/https://project-awesome.org/sporto/awesome-elm}} |
|||
{{程序设计语言}} |
{{程序设计语言}} |
2023年5月7日 (日) 19:56的最新版本
![]() | |
编程范型 | 函数式 |
---|---|
設計者 | Evan Czaplicki |
发行时间 | 2012年3月30日[1] |
当前版本 |
|
型態系統 | 静态, 强类型, 类型推论 |
許可證 | 宽松许可证 (三条款BSD许可证)[2] |
文件扩展名 | .elm |
網站 | elm-lang |
啟發語言 | |
Haskell, Standard ML, OCaml, F# | |
影響語言 | |
Redux,[3] Vuex[4] |
Elm是一个领域特定编程语言,用于声明式地创建基于web浏览器的图形用户界面。Elm是纯函数式的,开发它时强调了易用性、性能和健壮性。它宣传为“实际上没有运行时间异常”[6],Elm编译器的静态类型检查使之成为可能。
历史
[编辑]Elm最初由Evan Czaplicki在2012年作为毕业论文《Elm:用于函数式GUI的并发FRP》而设计的[7]。Elm的首次发行带有很多例子和一个在线编辑器,使得易于在web浏览器中试验它[8]。Evan在2013年加入Prezi从事Elm的工作[9],并在2016年转移到NoRedInk作为开源工程师,启动了Elm软件基金会[10]。
Elm编译器的最初实现执行目标为HTML、CSS和JavaScript[11]。核心工具集持续的扩展,现在包括了REPL[12]、包管理器[13]、时间旅行调试器[14]和针对macOS及Windows的安装器[15]。 Elm还有一个生态系统,包括社区创建的库[16]和Ellie[17],它是一个高级在线编辑器,允许保存工作和包含社区库。
特征
[编辑]Elm有一个小集合的语言构造,包括传统的if表达式,let表达式用于局部状态,和case表达式用于模式匹配[18]。作为函数式语言,它缺省的支持匿名函数,函数作为实际参数,和部份应用。它的语义包括不可变的值,无状态函数,和具有类型推论的静态类型。Elm程序通过虚拟的DOM呈现HTML,还可以使用“JavaScript作为服务”来与其他代码进行互操作。
不可变性
[编辑]在Elm中所有的值都是不可变的,这意味着一个值不能在创建之后修改。Elm使用持久性数据结构来实现它的Array
、Dict
和Set
库[19]。
静态类型
[编辑]Elm是静态类型的。类型标注(annotation)是可选的(由于有类型推论)但强烈鼓励。标注存在于定义之上的一行(不同于C家族语言,这里的类型和名字是夹杂在一起的)。Elm使用单一的冒号表达“拥有类型”。
类型包括原始类型如整数和字符串,和基本数据结构比如列表、元组和记录。函数拥有用箭头写成的类型,例如round : Float -> Int
。定制类型允许编程者建立定制类型,以匹配特定问题领域的方式来表示数据[20]。
类型可以推论出其他类型,例如List Int
。类型总是首字母大写;小写名字是类型变量。例如,List a
是未知类型的值的列表。它是空列表和给List.length
的实际参数的类型,对于这个列表的元素而言它是不可知的。有一些特殊类型,编程者建立用来与Elm运行时进行交互。例如,Html Msg
表示(虚拟)DOM树,其事件处理类型Msg
的所有产生消息。
不再允许任何值是隐含的可空值(比如JavaScript的undefined
或空指针),Elm的标准库定义了Maybe a
类型。产生或处理一个可选值的代码不显式的使用这个类型,而所有其他代码得到保证声称了类型的值是实际上存在的。
Elm提供有限数目的内建类型类:number
,它包括Int
和Float
,用来利用数值算符比如(+)
或(*)
;comparable
,它包括数值、字符、字符串、可比较者的列表和可比较者的元组,用来利用比较算符;和appendable
,它包括字符串和列表,用来利用(++)
进行串接。Elm不提供将定制类型包括入这些类型类,或建立新类型类的机制(参见限制章节)。
模块系统
[编辑]Elm拥有模块系统来允许用户将其代码分解到叫做模块的更小的部份之中。模块可以隐藏实现细节比如帮助函数,并组织有关的代码在一起。模块为可导入代码充当名字空间,比如Bitwise.and
。第三方库(或包)构成自一个或多个模块,并可从Elm公共库中获得到[21]。所有的库都采用语义版本号,这是编译器和其他工具所强制的。就是说,移除一个函数或改变它的类型只能在主要发行中进行。
同HTML、CSS和JavaScript的互操作
[编辑]Elm使用叫做端口的抽象来与JavaScript通信[22]。它允许值流入和流出Elm程序,确使了在Elm和JavaScript之间的通信。
Elm有一个叫做elm/html的库,编程者可以用来在Elm内书写HTML和CSS[23]。它使用虚拟DOM方式来使更新有效率[24]。
后端
[编辑]Elm官方上不支持服务器端开发。核心开发团队不将它作为主要目标考虑,并且偏好聚焦于在增进前端开发体验上的开发。尽管如此,有一些独立的计划,它们尝试探索将Elm用于后端的可能性。这些计划主要系附于Elm版本0.18.0,因为更新的版本不支持“原生”代码和其他可利用特征。有两个尝试将Elm用在BEAM(Erlang虚拟机)之上。其中一个计划直接在这个环境上执行Elm[25],而另一个计划把它编译成Elixir[26]。还有一个尝试通过Node.js下部结构为Elm建立后端框架[27]。这些计划都没有准备好用于生产。
Elm架构
[编辑]Elm架构是建造交互式web应用的模式。Elm应用本质上以这种方式来构造,但是其他项目可能发现这个概念很有用。
Elm程序总是分解成三个部份:
- 模型:这个应用的状态,
- 视图:一个把模型转变成HTML的函数,
- 更新:一个基于消息更新模型的函数。
这些是Elm架构的核心。
例如,想象显示一个数值和在按下时增加这个数值的一个按钮的一个应用[28]。在这种情况下,所有我们需要存储的是一个数值,所以我们的模型可以简单的就是type alias Model = Int
。view
函数将用Html
库来定义并显示这个数值和按钮。为了让这个数值被更新,我们需要能够向update
函数发送消息,这是通过定制类型比如type Msg = Increase
来完成的。 Increase
值被附着于在view
函数内定义的按钮,使得在用户点击这个按钮的时候,Increase
被传递到update
函数之上,它可以通过增加这个数值来更新这个模型。
在Elm架构中,发送消息至update
是改变状态的唯一方式。在更加复杂的应用中,消息可以来自各种来源:用户交互,模型初始化,来自update
的内部调用,订阅的外部事件(窗口改变大小、系统时钟、JavaScript互操作等等)和URL变更及请求。
限制
[编辑]Elm不支持高种类多态[29],这是同为函数式的语言Haskell和PureScript所提供的,Elm还不支持创建类型类。
这意味着,例如Elm没有跨越多种数据结构如List
和Set
的通用的map
函数。在Elm中,这种函数典型的要限定上它们的模块名字来调用,例如调用List.map
和Set.map
。在Haskell或PureScript中,只有一个函数map
。自从2015年这就是在Czaplicki的粗略路线图上的一个周知的特征要求[30]。
另一个缺陷是在中到大型项目中有大量的样板代码,如《Elm in Action》作者在他们的单一页面应用例子中所展示的那样[31],具有几乎同样的片段被重复于更新、视图、订阅、路由解析和建造函数之中。
样例代码
[编辑]下面的例子代码通过注释展示了Elm的基本特征:
-- 这是一个单一行注释。
{-
这是一个多行注释。
它是 {- 可嵌套的。 -}
-}
-- 这里定义叫做greeting的一个值。类型被推论为String。
greeting =
"Hello World!"
-- 对顶层声明最好增加类型标注。
hello : String
hello =
"Hi there."
-- 函数以相同方式声明,具有跟随在函数名字后的实际参数。
add x y =
x + y
-- 再次的,最好增加类型标注。
hypotenuse : Float -> Float -> Float
hypotenuse a b =
sqrt (a^2 + b^2)
-- 函数可以柯里化;这里我们柯里化乘法中缀算符于数2之上。
multiplyBy2 : number -> number
multiplyBy2 =
(*) 2
-- If表达式用于在Bool值上的分支。
absoluteValue : number -> number
absoluteValue number =
if number < 0 then negate number else number
-- 记录用来持有命名字段。
book : { title : String, author : String, pages : Int }
book =
{ title = "Steppenwolf"
, author = "Hesse"
, pages = 237
}
-- 记录访问通过 . 来进行。
title : String
title =
book.title
-- 记录访问 . 也可以用作一个函数。
author : String
author =
.author book
-- 可以通过type关键字建立标签联合。
-- 下列值表示一个二叉树。
type Tree a
= Empty
| Node a (Tree a) (Tree a)
-- 可以用过case表达式检测这些类型。
depth : Tree a -> Int
depth tree =
case tree of
Empty ->
0
Node value left right ->
1 + max (depth left) (depth right)
参见
[编辑]- PureScript:一个强类型的、纯函数式的编译成JavaScript的编程语言。
- Reason:OCaml的语法扩展和工具链,也可以转译成JavaScript。
- 函数式响应式编程
引用
[编辑]- ^ Czaplicki, Evan. My Thesis is Finally Complete! "Elm: Concurrent FRP for functional GUIs". Reddit. [2021-02-27]. (原始内容存档于2021-04-13).
- ^ elm/compiler. GitHub. [2021-02-27]. (原始内容存档于2019-03-21).
- ^ Prior Art - Redux. redux.js.org. [2021-02-27]. (原始内容存档于2020-09-21).
- ^ Comparison with Other Frameworks — Vue.js. [2021-02-27]. (原始内容存档于2021-05-03).
- ^ 存档副本. [2021-02-27]. (原始内容存档于2020-12-18).
- ^ Elm home page. [2021-02-27]. (原始内容存档于2021-05-07).
- ^ Czaplicki, Evan. Elm: Concurrent FRP for Functional GUIs (PDF). [2021-02-27]. (原始内容 (PDF)存档于2021-04-16).
csmith111. Programming with Elm-Signals.
Czaplicki, Evan. A Farewell to FRP. elm. [14 July 2018]. (原始内容存档于2019-05-31).When I started working on my thesis in 2011, I stumbled upon this academic subfield called Functional Reactive Programming (FRP). By stripping that approach down to its simplest form, I ended up with something way easier to learn than similar functional languages. Signals meant piles of difficult concepts just were not necessary in Elm. ……
As The Elm Architecture emerged, it became clear that you could do almost all your Elm programming without thinking about signals at all. ……
In the end, it was possible to remove signals because Elm has been moving towards an explicit emphasis on concurrency for quite some time now. ……Just like with my thesis, Concurrent FRP, the goal is to get the benefits of concurrency for free. ……
Note: Interested readers may find Lucid Synchrone interesting. Unfortunately for me, I had no idea my thesis had so much in common with synchronous programming languages at the time, but the connections are quite striking. I might argue that Elm was never about FRP. - ^ Try Elm. elm-lang.org. [2019-07-24]. (原始内容存档于2017-05-21).
- ^ elm and prezi. elm-lang.org. [2021-02-27]. (原始内容存档于2021-04-17).
- ^ new adventures for elm. elm-lang.org. [2021-02-27]. (原始内容存档于2021-04-17).
- ^ elm/compiler. GitHub. [2021-02-27]. (原始内容存档于2021-04-14).
- ^ repl. elm-lang.org. [2021-02-27]. (原始内容存档于2019-11-27).
- ^ package manager. elm-lang.org. [2021-02-27]. (原始内容存档于2020-09-18).
- ^ Home. elm-lang.org. [2021-02-27]. (原始内容存档于2020-12-03).
- ^ Install. guide.elm-lang.org. [2021-02-27]. (原始内容存档于2019-07-24).
- ^ community created libraries. [2021-02-27]. (原始内容存档于2015-02-11).
- ^ Ellie. [2022-05-12]. (原始内容存档于2021-01-22).
- ^ syntax. elm-lang.org. [2013-05-31]. (原始内容存档于2016-03-13).
- ^ elm/core. package.elm-lang.org. [2021-02-28]. (原始内容存档于2021-04-17).
- ^ Model The Problem. Elm. [4 May 2016]. (原始内容存档于2020-11-11).
- ^ Elm Public Library. [2021-02-27]. (原始内容存档于2021-05-19).
- ^ JavaScript interop. elm-lang.org. [2021-02-28]. (原始内容存档于2021-05-21).
- ^ elm/html. package.elm-lang.org. [2021-02-28]. (原始内容存档于2021-05-11).
- ^ Blazing Fast HTML. elm-lang.org. [2021-02-28]. (原始内容存档于2020-09-18).
- ^ 存档副本. [2021-02-28]. (原始内容存档于2020-09-08).
- ^ 存档副本. [2021-02-28]. (原始内容存档于2021-01-04).
- ^ 存档副本. [2021-02-28]. (原始内容存档于2020-11-22).
- ^ Buttons · An Introduction to Elm. guide.elm-lang.org. [2020-10-15]. (原始内容存档于2020-11-11).
- ^ Higher-Kinded types Not Expressible? #396. github.com/elm-lang/elm-compiler. [6 March 2015].
- ^ Higher-Kinded types Not Expressible #396. github.com/elm-lang/elm-compiler. [19 November 2019]. (原始内容存档于2020-12-18).
- ^ Main.elm. github.com/rtfeldman/elm-spa-example. [30 June 2020].
外部链接
[编辑]- 官方网站
- Awesome Elm. [2021-03-02]. (原始内容存档于2021-01-17).
|