英文原文:Elixir Design Goalscss
在去年,咱们已经在各类技术会议上讨论Elixir,咱们通常从介绍Erlang VM开始, 接着讨论Elixir的目标,抽出一些时间作现场演示,好比展现一些像是在两个分布式节点交换信息,甚至热更新代码等等。html
这篇文章总结这些讲座的内容,主要关注ELixir语言的目标: 兼容性(compatibility)
、生产力(productivity)
和可扩展性(extensibility)
。web
Elixr 兼容Erlang VM以及现有的生态系统,当咱们讨论Erlang时,通常来讲主要三部分:算法
Elixir
和Erlang
运行在同样的虚拟机上,而且兼容OTP。固然不只仅这些,全部的Erlang生态系统的工具,库也能够用于Elixir,而且在Elixir中调用Erlang代码不存在性能成本,反之亦然。编程
咱们常常说Erlang VM
是Elixir
最宝贵的资产。vim
全部的Elixir代码在轻量级的进程process(actors)
中执行,每个进程(process)
都有本身的状态,彼此之间交换消息。Erlang VM 将这些进程分发到多个cpu核心运行,使程序很是容易的并行
。segmentfault
事实上,若是你编译过Elixir代码,包括Elixir的源代码,你会发现全部的cpu核心都在运转。随着并行技术 变得更加简单和实惠,你很难忽略Erlang VM带给咱们的实惠。数据结构
最后,Erlang VM旨在构建永久运行,可以自我修复和大规模可扩展的系统。JoeArmstrong
,Erlang的建立者,最近出了一个关于OTP和Erlang VM背后的设计思想讲座。并发
Erlang也是新的东西, 一些开源项目好比像CouchDB, Riak, RabbitMQ, Chef11等,还有像公司好比Ericsson, Heroku, Basho, Klarna 和 Wooga 已经从 Erlang VM的优秀特性中受益, 其中一些使用Eralng VM 已经至关长的时间框架
Now we need to go meta. We should now think of a language design as being a
pattern for language designs. A tool for making more tools of the same kind. [...]
A language design can no longer be a thing. It must be a pattern, a pattern for
growth. A pattern for growing a pattern, for defining the patterns that
programmers can use for their real work and main goals.
-- Guy Steele, keynote at the 1998 ACM OOPSLA conference on "Growing a Language"
很难具体的去衡量一门语言的生产力,可以高效开发桌面应用的语言在数学计算方面可能会捉襟见肘。高生产力与你使用这门语言指望从事的领域,生态系统中的可用工具,以及是否能能够方便的创造和扩展这些工具备关。
基于这个缘由,Elixir语言核心实现的很是简约
。例如,在许多编程语言里,if,case, try
这些关键字都须要专门的语法分析规则去分析,而在Elixir里,这些只是宏(macros)
,这样作的好处就是开发者按能够照本身的需求去扩展语言。
这里有个例子如何在Elixir里实现一个unless
, unless
是不少语言的关键字
defmacro unless(expr, opts) do quote do if(!unquote(expr), unquote(opts)) end end unless true do IO.puts "this will never be seen" end
由于宏
接收代码(Elixir term)做为参数,咱们能够在编译时很是简单的把unless
转换在if
宏(Macros)也是Elixir元编程(Meta-programming)
的构建基础:编写生成代码的代码的能力。元编程可让开发者摆脱语言的束缚,创造强大的工具。在讲座中常常提到的一个常见例子是如何使用宏让测试框架更有表现力。让咱们看一个例子:
ExUnit.start defmodule MathTest do use ExUnit.Case, async: true test "adding two numbers" do assert 1 + 2 == 4 end end
注意到的第一件事是async: true
选项,当你的测试代码没有任何负做用(side-effect)的时候,能够经过async: true
选项设定以并发运行测试。
下一步,咱们使用assert
宏定义了一个断言。直接调用 assert
是一个糟糕的实践,由于错误报告不可读。在Elixir中,推荐的方法是使用 assertEqual
或者 assert_equal
执行断言
在Elixir中,assert
是一个宏,所以,它可以操做传入的断言代码,并进行推断。这段代码,在测试运行的时候提供了详细的错误报告:
1) test adding two numbers (MathTest) ** (ExUnit.ExpectationError) expected: 3 to be equal to (==): 4 at test.exs:7
这个简单的例子中,开发人员能够利用宏来提供一个简洁但功能强大的API。宏能够访问整个编译环境,可以检查导入的函数,宏, 定义变量等等。
这些例子很是简单,咱们可使用Elixir的宏实现更多的东西。例如,咱们正在使用宏实现一个web应用的路由功能,能够编译成一系列被VM高度优化的模式(patterns)。最终提供一个高度的表现力,高度优化的路由算法。
宏系统也对语法有着巨大的影响, 这也是咱们最后要讨论的。
尽管许多关于编程语言的讨论一开始就讨论语法,可是,对于Elixir,从没把提供”另外一套不一样的语法“做为它的目标。自从咱们想在Elixir中提供一个宏系统,咱们知道若是把Elixir的语法以一个简单直接的方式表达为Erlang的数据结构会是一个很是明智的作法。有了这个目标,咱们设计了第一个Elixir版本,看起来是这样的:
defmodule(Hello, do: ( def(calculate(a, b, c), do: ( =(temp, *(a, b)) +(temp, c) )) ))
在上面的代码片断,咱们表示了一切,除了变量,函数或宏调用。像关键字参数do:
在第一个版本已经存在。对此,咱们慢慢地加入新的语法,使得一些常见的模式更优雅,同时保持相同的底层数据表示形式。咱们很快就增长了运算符中缀表示法:
defmodule(Hello, do: ( def(calculate(a, b, c), do: ( temp = a * b temp + c )) ))
下一步是使用括号做为可选的:
defmodule Hello, do: ( def calculate(a, b, c), do: ( temp = a * b temp + c ) )
最后,咱们使用do/end 来替代 do:(...)结构:
defmodule Hello do def calculate(a, b, c) do temp = a * b temp + c end end
因为我先前的Ruby背景,很天然的会从Ruby借鉴一些。但这些只是副产品,不是语言目标。
不少语言结构也受到Erlang的启发,像是控制流宏,操做符和容器,好比下面的Elixir代码:
# 一个元组 tuple = { 1, 2, 3 } # 两个列表合成一个 [1,2,3] ++ [4,5,6] # Case case expr do { x, y } -> x + y other when is_integer(other) -> other end
Erlang是这样的:
% 一个元组 Tuple = { 1, 2, 3 }. % 两个列表合成一个 [1,2,3] ++ [4,5,6]. % Case case Expr of { X, Y } -> X + Y; Other when is_integer(Other) -> Other end.
Elixir构建在一个很是小的的核心之上,大部分的语言结构能够经过DSL的方式替换和扩展。固然,Elixir天生
擅长某些特定的领域,好比构建并发和分布式的应用,感谢OTP
和Erlang VM
。
Elixir 以标准库的形式补充了下面的领域:
上面大多数的特性也都提供本身的扩展机制,好比,num模块,Enum模块容许咱们对range,list,set
这些数据类型进行迭代。例如:
list = [1,2,3] Enum.map list, fn(x) -> x * 2 end #=> [2,4,6] range = 1..3 Enum.map range, fn(x) -> x * 2 end #=> [2,4,6] set = HashSet.new [1,2,3] Enum.map set, fn(x) -> x * 2 end #=> [2,4,6]
不只如此,任何开发人员均可以对任何数据类型实现Enum模块
的功能,只要对这种类型实现了Enumerable协议(Elixir的协议源于Clojure的协议),这是很是方便的,由于开发者只须要知道Enum的API就能够,而不用考虑set,list,dict的特定类型的API
语言自己还内置不少其它的协议,好比Inspect
协议用于打印数据结构,Access
协议能够经过key访问key-value
类型的数据。经过良好的扩展性,Elixir确保开发人员能够方便的使用语言完成工做。
这篇文章的总结了Elixir的设计目标:兼容性,生产力,扩展性
。基于Erlang VM,咱们为开发者提供了另
一套强大的工具链去构建并发,分布式,容错的系统。
咱们也很能够看到Elixir给Erlang VM带来了什么,特别是,基于宏的元编程系统, 多态结构,API比较一致的标准库,包括严格和惰性求值,unicode的处理,自带的测试框架等等。
想试下Elixir的话,能够从getting started guide开始