2024-01-31 Why I love Erlang


我想起了《黑客与画家》中的一段话:“编程语言不一样,与其说它是技术,还不如说是程序员的思考模式。编程语言是技术和宗教的混合物。”

Why I love Erlang

这本身就不是一个问题,喜欢某个编程语言就像喜欢某个具体的人一样,那是一种感觉,根本不需要具体的理由。

多年来,我一直很向往 DHH 因为他很早找到了他喜欢的编程语言 Ruby。我尝试过很多编程语言,如:Java、JS、Perl、Swift、ResonML 等等,很遗憾它们都没有让我有 soulmate 的感觉。几年前偶然的机会,我了解到 Elixir,以及断断续续地使用过程中又了解到 Erlang,编写 Erlang/Elixir 代码让我有了久违的愉悦感。

我愈发地明晰了 Erlang/Elixir 是我真正的 soulmate language,我太喜欢它们了。希望我可以像 DHH 对 Ruby 一样,为 Erlang/Elixir 做一些贡献。

虽然事实如上,但是我也可以列出一些具体的点说明为什么我喜欢 Erlang。

我不太确定应该按照 Erlang 的强项开始写,还是按照阅读这篇文章的朋友可以学习曲线开始写。
暂时先按照容易理解的顺序开始写吧。

TR;DR

  1. Erlang 让程序回归数学
  2. Erlang 整数不会溢出
  3. Erlang 提供完美的字面量对象
  4. Erlang 远程调用和本地调用一样简单
  5. Erlang 远程处理错误允许优雅地对应不可抗力因素
  6. Erlang 在语言层面提供了功能强大的 Schemaless Database

1. Erlang 让程序回归数学

列举计算机编程问题中常被提到的两个算法斐波拉切数和快速排序。

斐波那契数:

fib(0) -> 0;
fib(1) -> 1;
fib(X) -> fib(X-1) + fib(X-2).

快速排序

sort([]) -> [];
sort([Pivot|Rest]) ->
    {Smaller, Larger} = lists:partition(fun(X) -> X < Pivot end, Rest),
    sort(Smaller) ++ [Pivot] ++ sort(Larger).

我想应该没有其他编程语言可以做到像 Erlang 这样既优雅又简洁了吧。最重要的是 Erlang 编写的代码和数学上的定义几乎是一致的,太棒了。

再分享一个简单的求面积的函数

area({rectangle, Width, Ht}) -> Width * Ht;
area({circle, R})            -> 3.14 * R * R.

area({circle, 14}). % 615.44

Erlang 提供的函数参数模式匹配让代码可以减少很多条件判断,例如: if (rectangle) then ... else if (circle) then ... 等等。

2. Erlang 整数不会溢出

1234567890 * 9876543210.
% 12193263111263526900

相信所有开发者都知道编程领域绕不开的就是浮点数精度问题,如:0.1 + 0.2 不等于 0.3。

虽然 Erlang 也没有办法避免这个问题,并且和其他编程技巧一样也是先使用整数进行数学运算再除以位数;但是整数不溢出可以将运算范围和精度提升到其他编程语言无法比拟的水平。重要的是,这是语言默认提供的能力,不需要额外安装依赖。

3. Erlang 提供完美的字面量对象

Less, but better.

Rams

Erlang 中返回一个 person 数据

{person, {tj, 31, male}}

虽然我很喜欢 JSON,相较于 Erlang tuple ,还是有点繁琐了。

{
    "name": "tj",
    "age": 31,
    "gender": "male"
}

Erlang Records 提供更加明确属性名,或许大家更亲切。

-record(person, {name, phone, address}).

P = #person{name="tj"}
#person{name = N} = P.

N. % "tj"

— 下面分享一些 Erlang 更高级的功能 —

4. Erlang 在语言层面提供远程调用,原生支持分布式

Erlang 允许直接通过 node 调用远程代码,在语言层面支持分布式。

我们准备一段代码

% math.erl
-module(math).
-export([add/2]).

add(X, Y) ->
    X + Y.

然后在代码目录下开启一个 terminal,并打开一个指定名称的 erl

erl -sname left

node().
% 'left@2022-M2-Air'

编译代码,并测试一下代码是否工作

c(math).
% {ok,math}
math:add(1,2).
% 3

任意目录 下开启 另一个 terminal,并打开一个指定名称的 erl

erl -sname right

node().
% 'right@2022-M2-Air'

现在是见证奇迹的时刻了。虽然在 right terminal 没有 math.erl 代码, Erlang 允许我们直接调用远程节点的代码

math:add(1,2).
% ** exception error: undefined function math:add/2

rpc:call('left@2022-M2-Air', math, add, [1,2]).
% 3

5. Erlang 远程处理错误允许优雅地对应不可抗力因素

远程处理错误这不是微服务架构的终极目标吗?

准备两个 server side 代码,server1 负责逻辑,server2 负责错误处理。

% server1.erl
-module(sever1).
-export([run/0]).

run() ->
    receive
        X -> list_to_atom(X)
    end.
% server2.erl
-module(server2).
-export([listen/1]).

listen(Pid) ->
    spawn(fun() ->
        process_flag(trap_exit, true),
        link(Pid),
        receive
            {'EXIT', Pid, _} -> io:format(" ~p died. ~n", [Pid])
        end
    end).

打开一个 terminal 并编译 server1

erl -sname server1

c(server1).

打开另外一个 terminal,并编译 server2

erl -sname server2

c(server2).

在 terminal 2 中

% 创建一个线程指向 server1 run 函数
Pid = spawn('server1@2022-M2-Air', server1, run, []).

% 绑定线程和错误处理函数
server2:listen(Pid).

% 向线程发送消息
Pid ! hello.

这时 terminal 2 会得到如下输出

<10155.111.0> died. 

so cool.

解释一下,虽然程序异常是在 terminal 1 发生的,但是处理程序却只在 terminal 2 中被定义,并且在 terminal 中被执行。

现在我们先停下来,回味一下前面这个样例。这个样例展示了 Erlang 哲学中极其重要的一面——远程错误处理。

joe

Erlang 在语言层面提供了一个 k8s

TJ 2024-01-31
  1. 6. Erlang 在语言层面提供了功能强大的 Schemaless Database

其实我没有使用过 Erlang 自带 Mnesia database,而且也没有计划真正使用 Mnesia 开发实际产品。但是我很喜欢 ETS 和 DETS,在语言层面提供 ETS DETS 这种内存和硬盘储存服务真的太方便了。

虽然 SQLite 也很方便,但是 ETS 可以直接存储 Erlang Records 这简直是无敌一样的存在。

1> Tab = ets:new(user, [set]).
#Ref<0.2226659868.3932815361.70843>
2> ets:insert(Tab, {tj, {tj, 31, male}}).
true
3> ets:lookup(Tab, tj).
[{tj,{tj,31,male}}]

为什么 Erlang 中 ETS EDTS 比 SQLite 更好用?

  1. ETS EDTS 无需额外安装,Erlang VM 自带
  2. ETS EDTS 支持存储 Erlang Records,原生对象,更高效,无需额外转换
  3. ETS EDTS 支持存储任何 Erlang Records,即使是嵌套数据,相当于一个 NoSQL database。

先写到这吧,如果你想尝试 Erlang,或者有 Erlang 相关讨论想要找人聊聊,欢迎来找我,😁

I love Elixir too, Elixir runs on the Erlang VM and has a lot of beautiful features and awesome developers.

TJ 2024-01-31