fbpx
维基百科

Elm语言

Elm是一个领域特定编程语言,用于声明式地创建基于web浏览器图形用户界面。Elm是纯函数式的,开发它时强调了易用性、性能和健壮性。它宣传为“实际上没有运行时间异常[6],Elm编译器的静态类型检查使之成为可能。

Elm
编程范型函数式
設計者Evan Czaplicki
发行时间2012年3月30日,​11年前​(2012-03-30[1]
目前版本
  • 0.19.1 (2019年10月21日)
型態系統静态, 强类型, 类型推论
許可證宽松许可证 (三条款BSD许可证)[2]
文件扩展名.elm
網站elm-lang.org
啟發語言
Haskell, Standard ML, OCaml, F#
影響語言
Redux,[3] Vuex[4]

历史

Elm最初由Evan Czaplicki在2012年作为毕业论文《Elm:用于函数式GUI的并发FRP》而设计的[7]。Elm的首次发行带有很多例子和一个在线编辑器,使得易于在web浏览器中试验它[8]。Evan在2013年加入Prezi从事Elm的工作[9],并在2016年转移到NoRedInk英语NoRedInk作为开源工程师,启动了Elm软件基金会[10]

Elm编译器的最初实现执行目标为HTMLCSSJavaScript[11]。核心工具集持续的扩展,现在包括了REPL[12]包管理器[13]、时间旅行调试器[14]和针对macOS及Windows的安装器[15]。 Elm还有一个生态系统,包括社区创建的库[16]和Ellie[17],它是一个高级在线编辑器,允许保存工作和包含社区库。

特征

Elm有一个小集合的语言构造,包括传统的if表达式,let表达式用于局部状态,和case表达式用于模式匹配[18]。作为函数式语言,它缺省的支持匿名函数,函数作为实际参数,和部份应用。它的语义包括不可变的值,无状态函数,和具有类型推论的静态类型。Elm程序通过虚拟的DOM呈现HTML,还可以使用“JavaScript作为服务”来与其他代码进行互操作。

不可变性

在Elm中所有的值都是不可变的,这意味着一个值不能在创建之后修改。Elm使用持久性数据结构来实现它的ArrayDictSet[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,它包括IntFloat,用来利用数值算符比如(+)(*)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 = Intview函数将用Html库来定义并显示这个数值和按钮。为了让这个数值被更新,我们需要能够向update函数发送消息,这是通过定制类型比如type Msg = Increase来完成的。 Increase值被附着于在view函数内定义的按钮,使得在用户点击这个按钮的时候,Increase被传递到update函数之上,它可以通过增加这个数值来更新这个模型。

在Elm架构中,发送消息至update是改变状态的唯一方式。在更加复杂的应用中,消息可以来自各种来源:用户交互,模型初始化,来自update的内部调用,订阅的外部事件(窗口改变大小、系统时钟、JavaScript互操作等等)和URL变更及请求。

限制

Elm不支持高种类多态[29],这是同为函数式的语言HaskellPureScript所提供的,Elm还不支持创建类型类

这意味着,例如Elm没有跨越多种数据结构如ListSet的通用的map函数。在Elm中,这种函数典型的要限定上它们的模块名字来调用,例如调用List.mapSet.map。在Haskell或PureScript中,只有一个函数map。自从2015年这就是在Czaplicki的粗略路线图上的一个周知的特征要求[30]

另一个缺陷是在中到大型项目中有大量的样板代码英语Boilerplate code,如《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) 

参见

引用

  1. ^ Czaplicki, Evan. . Reddit. [2021-02-27]. (原始内容存档于2021-04-13). 
  2. ^ . GitHub. [2021-02-27]. (原始内容存档于2019-03-21). 
  3. ^ . redux.js.org. [2021-02-27]. (原始内容存档于2020-09-21). 
  4. ^ . [2021-02-27]. (原始内容存档于2021-05-03). 
  5. ^ . [2021-02-27]. (原始内容存档于2020-12-18). 
  6. ^ . [2021-02-27]. (原始内容存档于2021-05-07). 
  7. ^ Czaplicki, Evan. (PDF). [2021-02-27]. (原始内容 (PDF)存档于2021-04-16). 
    csmith111. Programming with Elm-Signals. 
    Czaplicki, Evan. . 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.
     
  8. ^ . elm-lang.org. [2019-07-24]. (原始内容存档于2017-05-21). 
  9. ^ . elm-lang.org. [2021-02-27]. (原始内容存档于2021-04-17). 
  10. ^ . elm-lang.org. [2021-02-27]. (原始内容存档于2021-04-17). 
  11. ^ . GitHub. [2021-02-27]. (原始内容存档于2021-04-14). 
  12. ^ . elm-lang.org. [2021-02-27]. (原始内容存档于2019-11-27). 
  13. ^ . elm-lang.org. [2021-02-27]. (原始内容存档于2020-09-18). 
  14. ^ . elm-lang.org. [2021-02-27]. (原始内容存档于2020-12-03). 
  15. ^ . guide.elm-lang.org. [2021-02-27]. (原始内容存档于2019-07-24). 
  16. ^ . [2021-02-27]. (原始内容存档于2015-02-11). 
  17. ^ . [2022-05-12]. (原始内容存档于2021-01-22). 
  18. ^ . elm-lang.org. [2013-05-31]. (原始内容存档于2016-03-13). 
  19. ^ . package.elm-lang.org. [2021-02-28]. (原始内容存档于2021-04-17). 
  20. ^ . Elm. [4 May 2016]. (原始内容存档于2020-11-11). 
  21. ^ . [2021-02-27]. (原始内容存档于2021-05-19). 
  22. ^ . elm-lang.org. [2021-02-28]. (原始内容存档于2021-05-21). 
  23. ^ . package.elm-lang.org. [2021-02-28]. (原始内容存档于2021-05-11). 
  24. ^ . elm-lang.org. [2021-02-28]. (原始内容存档于2020-09-18). 
  25. ^ . [2021-02-28]. (原始内容存档于2020-09-08). 
  26. ^ . [2021-02-28]. (原始内容存档于2021-01-04). 
  27. ^ . [2021-02-28]. (原始内容存档于2020-11-22). 
  28. ^ . guide.elm-lang.org. [2020-10-15]. (原始内容存档于2020-11-11). 
  29. ^ Higher-Kinded types Not Expressible? #396. github.com/elm-lang/elm-compiler. [6 March 2015]. 
  30. ^ . github.com/elm-lang/elm-compiler. [19 November 2019]. (原始内容存档于2020-12-18). 
  31. ^ Main.elm. github.com/rtfeldman/elm-spa-example. [30 June 2020]. 

外部链接

  • 官方网站  
  • . [2021-03-02]. (原始内容存档于2021-01-17). 

elm语言, elm是一个领域特定编程语言, 用于声明式地创建基于web浏览器的图形用户界面, elm是纯函数式的, 开发它时强调了易用性, 性能和健壮性, 它宣传为, 实际上没有运行时间异常, elm编译器的静态类型检查使之成为可能, elm编程范型函数式設計者evan, czaplicki发行时间2012年3月30日, 11年前, 2012, 目前版本0, 2019年10月21日, 型態系統静态, 强类型, 类型推论許可證宽松许可证, 三条款bsd许可证, 文件扩展名, elm網站elm, lang, org啟. Elm是一个领域特定编程语言 用于声明式地创建基于web浏览器的图形用户界面 Elm是纯函数式的 开发它时强调了易用性 性能和健壮性 它宣传为 实际上没有运行时间异常 6 Elm编译器的静态类型检查使之成为可能 Elm编程范型函数式設計者Evan Czaplicki发行时间2012年3月30日 11年前 2012 03 30 1 目前版本0 19 1 2019年10月21日 型態系統静态 强类型 类型推论許可證宽松许可证 三条款BSD许可证 2 文件扩展名 elm網站elm lang wbr org啟發語言Haskell Standard ML OCaml F 影響語言Redux 3 Vuex 4 目录 1 历史 2 特征 2 1 不可变性 2 2 静态类型 2 3 模块系统 2 4 同HTML CSS和JavaScript的互操作 2 5 后端 3 Elm架构 4 限制 5 样例代码 6 参见 7 引用 8 外部链接历史 编辑Elm最初由Evan Czaplicki在2012年作为毕业论文 Elm 用于函数式GUI的并发FRP 而设计的 7 Elm的首次发行带有很多例子和一个在线编辑器 使得易于在web浏览器中试验它 8 Evan在2013年加入Prezi从事Elm的工作 9 并在2016年转移到NoRedInk 英语 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 gt 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 另一个缺陷是在中到大型项目中有大量的样板代码 英语 Boilerplate code 如 Elm in Action 作者在他们的单一页面应用例子中所展示的那样 31 具有几乎同样的片段被重复于更新 视图 订阅 路由解析和建造函数之中 样例代码 编辑下面的例子代码通过注释展示了Elm的基本特征 这是一个单一行注释 这是一个多行注释 它是 可嵌套的 这里定义叫做greeting的一个值 类型被推论为String greeting Hello World 对顶层声明最好增加类型标注 hello String hello Hi there 函数以相同方式声明 具有跟随在函数名字后的实际参数 add x y x y 再次的 最好增加类型标注 hypotenuse Float gt Float gt Float hypotenuse a b sqrt a 2 b 2 函数可以柯里化 这里我们柯里化乘法中缀算符于数2之上 multiplyBy2 number gt number multiplyBy2 2 If表达式用于在Bool值上的分支 absoluteValue number gt number absoluteValue number if number lt 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 gt Int depth tree case tree of Empty gt 0 Node value left right gt 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 取自 https zh wikipedia org w index php title Elm语言 amp oldid 77145524, 维基百科,wiki,书籍,书籍,图书馆,

文章

,阅读,下载,免费,免费下载,mp3,视频,mp4,3gp, jpg,jpeg,gif,png,图片,音乐,歌曲,电影,书籍,游戏,游戏。