[Translation] Elixir 設計目標

英文原文:Elixir Design Goalscss

請輸入圖片描述

在去年,咱們已經在各類技術會議上討論Elixir,咱們通常從介紹Erlang VM開始, 接着討論Elixir的目標,抽出一些時間作現場演示,好比展現一些像是在兩個分佈式節點交換信息,甚至熱更新代碼等等。html

這篇文章總結這些講座的內容,主要關注ELixir語言的目標: 兼容性(compatibility)生產力(productivity)可擴展性(extensibility)web

兼容性(Compatibility)

Elixr 兼容Erlang VM以及現有的生態系統,當咱們討論Erlang時,通常來講主要三部分:算法

  • 一門叫Erlang的編程語言
  • 一系列設計原則,稱爲OTP
  • Erlang虛擬機,指的是EVM和BEAM

ElixirErlang運行在同樣的虛擬機上,而且兼容OTP。固然不只僅這些,全部的Erlang生態系統的工具,庫也能夠用於Elixir,而且在Elixir中調用Erlang代碼不存在性能成本,反之亦然。編程

咱們常常說Erlang VMElixir最寶貴的資產。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 已經至關長的時間框架

生產力(Productivity)

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裏實現一個unlessunless是不少語言的關鍵字

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天生
擅長某些特定的領域,好比構建併發和分佈式的應用,感謝OTPErlang VM
Elixir 以標準庫的形式補充了下面的領域:

  • Unicode 字符串 和 相應的 操做
  • 一個功能強大的單元測試框架
  • 更多的數據結構,包括新的集合和字典的實現
  • 多態紀錄
  • 嚴格和惰性的枚舉API
  • 便於腳本使用的函數,好比使用filesystem和path
  • 能夠編譯和測試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開始

相關文章
相關標籤/搜索