F's Blog

博客 收藏夹
Elixir

29 Sep 2017

Elixir 里可以看到很多 Ruby 的语法,比如经典的 do…end 程序块,可以说是对 Ruby 程序员的一个福利。 上手感觉不是如 Erlang 那么怪,而且可以使用 OTP,实现良好的并发性能。

等号是模式匹配。

变量的数据不可变,因此可以被复用。

Elixir 里的进程就像面向对象编程里的对象一样,它不是传统操作系统里的进程概念,很轻量。它们之间通过仅通过 send 消息传递信息。 其实在面向对象编程里,一个实例调用方法,也是相当于对这个实例发送消息,只是这个实例会立刻执行,没有 receive 环节,因此做不到完全的隔离。

函数式编程的一大特点,就是没有可变的变量来记录状态。因此,函数的每次执行,都是新的,如同 HTTP 的无状态请求。 而为了记录状态,每次需要把之前的状态作为函数的参数传回来。

这就是纯粹的函数编程,没有副作用,也就不需要锁,因此可以很容易实现并发。

函数编程里的循环真是漂亮:用递归实现。当 Elixir 发现最后的递归调用是最后一个执行时,会直接跳到函数的开始,而不是在程序栈里调用,因为返回值还是原函数,很干净,没有需要放到栈里东西。

Ruby 里的 map 和 reduce 方法,Python 里的推倒式,也让我找到了它们的出处,原来都是函数式编程的思想。

Elixir 是学 Ruby 的,而且改进了很多。比如 mix deps.get 会把依赖包的代码下载到本地。

主要语法

定义匿名函数 fn…end

定义模块 defmodule

定义函数 def

管道 |>

发送和接收消息 send receive

定义协议

定义宏 defmacro

宏是编写代码的代码,并返回生成的代码。 返回的代码会在宏外执行。在宏定义里的代码是会被解析执行的,那如果想要返回代码而不执行,一个是直接返回单个函数语句,如 IO.puts(“OK”),要么就用 quote 包裹着,quote 里面的代码是不会立刻执行的。但又想在 quote 里执行一些代码,比如在 stirng 里插入 #{1+2},这是就需要用 unquote 来包裹要立刻执行的代码。

而且宏并不是简单把代码返回插入,它也是有自己的独立空间的。 在 Ruby 里,是把代码写到 string 里直接插入,然后用 eval 执行。显然这里专门的宏定义语法更高级些。

递归

递归在函数编程里有举足轻重的地位,因为函数编程语言不能记录状态,那么状态的传递就是通过递归实现的。 反复调用一个函数,并传入前一个状态。

OTP

编程习惯

本文由 付豪 创作,采用署名 4.0 国际(CC BY 4.0)创作共享协议进行许可,详细声明