Erlang开发者或多或少都用过或者听说过Core erlang,它是什么样的呢?新建一个测试模块a.erl,如下操作会生成core erlang代码而非a.beam:
 
Eshell V6.0  (abort with ^G)
1> c(a,[to_core]).
这时文件夹中已经生成了一个a.core的文件,然后我们如下行事:
 
2> c(a,[from_core]).
{ok,a}

  

这时已经看到a.beam了,打开a.core的文件,这些看起来熟悉却又有点奇怪的代码是什么意思?有什么用呢?

What is Core Erlang?

Core Erlang 项目地址:  http://www.it.uu.se/research/group/hipe/cerl/

 
   目前Core Erlang项目由HIPE和OTP团队共同维护,项目首页上有两份非常重要的资料:语言规格说明和简介性质的论文
 
 
注:不想下载Postscript文件阅读器的,可以在线转换ps到PDF http://www.ps2pdf.com/

Why Core Erlang ?

Core Erlang 是Erlang的一种中间表现形式,Erlang在语法层面一直在演变,越发复杂,一些代码分析工具或者调试工具解读代码就不方便了.Core Erlang就是因此而生,它尽可能的保持语法简单,稳定以方便工具解析,同时具备代码可读性以方便手工修改代码.

换句话说,通过Core Erlang我们可以透过语法糖看到真实的代码逻辑是怎样的,在之前分析Erlang语法相关的博文中我就数次使用Core Erlang,比如:

[Erlang 0034] Erlang iolist  通过Core Erlang 查看iolists内部表示

http://www.cnblogs.com/me-sa/archive/2012/01/31/erlang0034.html

[Erlang 0039] Erlang Inheritance 通过Core Erlang看所谓的继承extends实际上是做了什么

http://www.cnblogs.com/me-sa/archive/2012/02/17/erlang0039.html

[Erlang 0058] Erlang Function调用效率 通过Core Erlang看几种函数调用方式性能差异是如何产生的

http://www.cnblogs.com/me-sa/archive/2012/05/06/erlang-function-call-efficiency.html

Core Erlang in Action

下面我将通过几段代码把常用的Core Erlang展示一下,模块定义和attitudes之类的基本上都能对应上就不说了,不求完备,但求实用,直接进入方法.准备好伙计,要开始战斗了!

第一段代码

append_list()->
[a,b] ++ [1,2]. append_list2(L)->
[100,200] ++L. append_list3(L) ->
L++[100,200].

  

对应的Core Erlang代码:

'append_list'/0 =
%% Line 5
fun () ->
['a'|['b'|[1|[2]]]]
'append_list2'/1 =
%% Line 8
fun (_cor0) ->
%% Line 9
[100|[200|_cor0]]
'append_list3'/1 =
%% Line 11
fun (_cor0) ->
%% Line 12
call 'erlang':'++'
(_cor0, [100|[200]])

  

这里就已经很好玩了对不对,所谓的函数,其实就是把lambda表达式(或者说Fun)赋值给变量.然后看append_list()由于结果是可以编译时计算出来的,所以做了优化,直接给出了结果.append_list2(L)也做了优化把两个元素挂在了表头.append_list3(L)没有什么优化余地老老实实call 'erlang':'++'

第二段代码

test()->
A=lists:seq(1,10),
B={1,2,3,4},
C= <<"42">>,
{M,N,P,Q} =B,
{[A,M],[P,Q],N,C}.

  

可以猜测一下这段代码对应的Core Erlang是什么样的?我把答案代码折叠一下

'test'/0 =
%% Line 14
fun () ->
let <A> =
%% Line 15
call 'lists':'seq'
(1, 10)
in %% Line 19
{[A|[1]],[3|[4]],2,#{#<52>(8,1,'integer',['unsigned'|['big']]),
#<50>(8,1,'integer',['unsigned'|['big']])}#}

  

这里我们特别要关注两点:1. let原语显示指定了变量的作用范围,是不是想到了下面的代码?

(define-syntax let
(syntax-rules ()
((let ((var expr) ...) body ...)
((lambda (var ...) body ...) expr ...)))) (let ((a 1) (b 2)) (+ a b))

  

2. 二进制数据<<"42">>在Core Erlang表达的时候会把默认的一些元数据描述出来,程序解析当然方便,人工阅读就显得繁琐了.

第三段代码

第三段代码纯粹是为了演示故意复杂化的,估计没有谁会会这样多此一举的写加法运算吧

add(A,B)->
case {A,B} of
{1,1} -> 2;
{0,0}-> 0;
{A,B} ->A +B
end.

  

Core Erlang代码就有趣的多了,不要被下面这堆东西吓到:

'add'/2 =
%% Line 21
fun (_cor1,_cor0) ->
%% Line 22
case <_cor1,_cor0> of
%% Line 23
<1,1> when 'true' ->
2
%% Line 24
<0,0> when 'true' ->
0
%% Line 25
<_cor5,_cor6>
when let <_cor7> =
call 'erlang':'=:='
(_cor5, _cor1)
in let <_cor8> =
call 'erlang':'=:='
(_cor6, _cor0)
in call 'erlang':'and'
(_cor7, _cor8) ->
call 'erlang':'+'
(_cor1, _cor0)
( <_fol6,_fol7> when 'true' ->
let <_cor2> = {_fol6,_fol7}
in primop 'match_fail'
({'case_clause',_cor2})
-| ['compiler_generated'] )
end

  

前面两个逻辑分支需要解释一下的就是match pattern的语法结构是<v1,v2>;需要仔细看的是第三个逻辑分支,可以看到模式匹配的细节其实是: _cor7 = (_cor5 =:=  _cor1), _cor8=((_cor6 =:=_cor0)),_cor7 and _cor8;并且后面还有编译期间自动生成的match_fail代码.

第四段代码

加强一下对match pattern的印象,看下面这段代码,够简单了吧,生成的Core Erlang代码同样会把逻辑补全:

match_test(T)->
{A,B,C} =T,
[A,{B,C}].

  

下一次我们看到模式匹配的时候,脑海中应该能浮现出下面的场景了吧:

'match_test'/1 =
%% Line 28
fun (_cor0) ->
%% Line 29
case _cor0 of
<{A,B,C}> when 'true' ->
%% Line 30
[A|[{B,C}|[]]]
( <_cor1> when 'true' ->
primop 'match_fail'
({'badmatch',_cor1})
-| ['compiler_generated'] )
end

  

第五段代码

我是列表解析的重度使用患者,特别是在Erlang Shell中,我把它当做循环,当做过滤器,当做if;当它转换成Core Erlang表示的时候,就呈现出其背后的机制:

lc_test()->
[Item * 2 || Item <- lists:seq(1,20),Item rem 2==0].

  

'lc_test'/0 =
%% Line 32
fun () ->
%% Line 33
( letrec
'lc$^0'/1 =
fun (_cor4) ->
case _cor4 of
<[Item|_cor1]>
when try
let <_cor2> =
call 'erlang':'rem'
(Item, 2)
in call 'erlang':'=='
(_cor2, 0)
of <Try> ->
Try
catch <T,R> ->
'false' ->
let <_cor5> =
call 'erlang':'*'
(Item, 2)
in let <_cor6> =
apply 'lc$^0'/1
(_cor1)
in ( [_cor5|_cor6]
-| ['compiler_generated'] )
( <[Item|_cor1]> when 'true' ->
apply 'lc$^0'/1
(_cor1)
-| ['compiler_generated'] )
<[]> when 'true' ->
[]
( <_cor4> when 'true' ->
( primop 'match_fail'
({'function_clause',_cor4})
-| [{'function_name',{'lc$^0',1}}] )
-| ['compiler_generated'] )
end
in let <_cor3> =
call 'lists':'seq'
(1, 20)
in apply 'lc$^0'/1
(_cor3)
-| ['list_comprehension'] )

  

这里要说的就是letrec 它让我们能够在 'lc$^0'/1内部调用 'lc$^0'/1自身.有兴趣的可以找更多关于letrec lisp的资料来看.

第六段代码

这段代码主要关注尾递归和Guard

fact(N) when N>0 ->
N * fact(N-1);
fact(0) ->
1.

  

'fact'/1 =

    %% Line 35

    fun (_cor0) ->

     case _cor0 of

       <N>

           when call 'erlang':'>'

              (_cor0,

               0) ->

           let <_cor1> =

            %% Line 36

            call 'erlang':'-'

                (N, 1)

           in  let <_cor2> =

                %% Line 36

                apply 'fact'/1

                 (_cor1)

            in  %% Line 36

                call 'erlang':'*'

                 (N, _cor2)

       %% Line 37

       <0> when 'true' ->

           %% Line 38

           1

       ( <_cor3> when 'true' ->

          ( primop 'match_fail'

                ({'function_clause',_cor3})

            -| [{'function_name',{'fact',1}}] )

         -| ['compiler_generated'] )

     end

  

第七段代码

看看所谓的函数分支是什么

dump(a)->atom_a;
dump([]) ->empty_list;
dump(C)->io:format("parameter is : ~p",[C]).

  

看下面的代码,其实所谓逻辑分支其实只是case语句中的逻辑分支而已,只不过要是在项目中写这样冗长的代码估计要疯掉了;语法上支持函数分支让我们可以写短函数,人工维护起来方便些.

'dump'/1 =
%% Line 40
fun (_cor0) ->
case _cor0 of
<'a'> when 'true' ->
'atom_a'
%% Line 41
<[]> when 'true' ->
'empty_list'
%% Line 42
<C> when 'true' ->
call 'io':'format'
([112|[97|[114|[97|[109|[101|[116|[101|[114|[32|[105|[115|[32|[58|[32|[126|[112]]]]]]]]]]]]]]]]], [C|[]])
end

  

第八段代码

当然少不了receive语句了

recv_test()->
receive
a-> "a";
m->io:format("Call M(),Result: ~p ",[m()]),recv_test();
{1,2} ->one_two;
H -> io:format("recv ~p",[H]),recv_test()
end.

  

看下面Core Erlang最后几句是不是恍然大悟,原来是这样啊

'recv_test'/0 =
%% Line 44
fun () ->
%% Line 45
receive
%% Line 46
<'a'> when 'true' ->
[97]
%% Line 47
<'m'> when 'true' ->
let <_cor0> =
apply 'm'/0
()
in do call 'io':'format'
([67|[97|[108|[108|[32|[77|[40|[41|[44|[82|[101|[115|[117|[108|[116|[58|[32|[126|[112|[32]]]]]]]]]]]]]]]]]]]], [_cor0|[]])
apply 'recv_test'/0
()
%% Line 48
<{1,2}> when 'true' ->
'one_two'
%% Line 49
<H> when 'true' ->
do call 'io':'format'
([114|[101|[99|[118|[32|[126|[112]]]]]]], [H|[]])
apply 'recv_test'/0
()
after 'infinity' ->
'true'

  

第九段代码

-record(person,{id=0,name}).

r(#person{id= ID ,name=Name} =P)->
{ID,Name}. r_test()->
P=#person{id=123 , name="zen"},
r(P).

  

这下看清楚record是什么了吧?

'r'/1 =
%% Line 56
fun (_cor0) ->
case _cor0 of
<P = {'person',ID,Name}> when 'true' ->
%% Line 57
{ID,Name}
( <_cor1> when 'true' ->
( primop 'match_fail'
({'function_clause',_cor1})
-| [{'function_name',{'r',1}}] )
-| ['compiler_generated'] )
end
'r_test'/0 =
%% Line 59
fun () ->
%% Line 61
apply 'r'/1
({'person',123,[122|[101|[110]]]})

  

第十段代码 

这一段应该算是赶潮流的代码,文档里面暂时还没有提到的Maps

m()->
M=#{1=>2 , a=>4,{100,200}=>[1,2,3],<<"zen">> => "Hello"},
#{{100,200} := Data} =M,
Data.

  

哇,Maps的Core Erlang表示还真是.....有些人又要说Erlang伤眼睛了

'm'/0 =
%% Line 63
fun () ->
let <_cor0> =
%% Line 64
~{::<1,2>,::<'a',4>,::<{100,200},[1|[2|[3]]]>,::<#{#<122>(8,1,'integer',['unsigned'|['big']]),
#<101>(8,1,'integer',['unsigned'|['big']]),
#<110>(8,1,'integer',['unsigned'|['big']])}#,[72|[101|[108|[108|[111]]]]]>}~
in %% Line 65
case _cor0 of
<~{~<{100,200},Data>}~> when 'true' ->
%% Line 66
Data
( <_cor2> when 'true' ->
primop 'match_fail'
({'badmatch',_cor2})
-| ['compiler_generated'] )
end

  

看过了上面的代码,我们可以想想Erlang在语法层面做了哪些设计让我们更容易表达想法,代码更简单,好了,就到这里了,假期愉快.

2014-4-10 10:41:08 补充

http://www.erlang.org/download/otp_src_17.0.readme

OTP-11547  The .core and .S extensions are now documented in the erlc  documentation, and the 'from_core' and 'from_asm' options are now documented in the compiler documentation. (Thanks to  Tuncer Ayaz.)

2014-10-21 14:38:56 再次补充

Abstraction and Model Checking of Core Erlang Programs in Maude

 
 
PHP-CoreErlang
PHP-CoreErlang is a DSL (domain specific language) for PHP, which generates "Core Erlang" .core files, which allows one to target the Erlang VM.
 
 
Erlang Types, Abstract Form & Core
 
 
Write A Template Compiler For Erlang
 
 
Implementing languages on the Erlang VM
 
 

 

[Erlang 0120] Know a little Core Erlang的更多相关文章

  1. Core Erlang:Erlang的Core中间表示

    随着erlang的不断发展,它的语法越来越复杂,不便于诸如分析器,调试器此类程序在源码层次直接进行解析,而CORE Erlang旨在为Erlang提供一个人类可读可改的中间表示(Intermediat ...

  2. [Erlang 0126] 我们读过的Erlang论文

    我在Erlang Resources 豆瓣小站上发起了一个征集活动 [链接] ,"[征集] 我们读过的Erlang论文",希望大家来参加.发起这样一个活动的目的是因为Erlang相 ...

  3. [Erlang 0115] 2014值得期待的Erlang两本新书

    在2014年的开头就有这样一个令人振奋的好消息,Erlang有一本新书即将出版 <The Erlang Runtime System>,其作者happi在2013年3月份公布了这本书的写作 ...

  4. [Erlang 0004] Centos 源代码编译 安装 Erlang

    原文地址: http://www.cnblogs.com/me-sa/archive/2011/07/09/erlang0004.html 由于最终部署的生产环境是Centos,所以我需要在Cento ...

  5. [Erlang 0129] Erlang 杂记 VI

    把之前阅读资料的时候记下的东西,整理了一下. Adding special-purpose processor support to the Erlang VM   P23 简单介绍了Erlang C ...

  6. [Erlang 0127] Term sharing in Erlang/OTP 上篇

    之前,在 [Erlang 0126] 我们读过的Erlang论文 提到过下面这篇论文: On Preserving Term Sharing in the Erlang Virtual Machine ...

  7. [Erlang 0125] Know a little Erlang opcode

    Erlang源代码编译为beam文件,代码要经过一系列的过程(见下面的简图),Core Erlang之前已经简单介绍过了Core Erlang,代码转换为Core Erlang,就容易拨开一些语法糖的 ...

  8. [Erlang 0122] Erlang Resources 2014年1月~6月资讯合集

    虽然忙,有些事还是要抽时间做; Erlang Resources 小站 2014年1月~6月资讯合集,方便检索.      小站地址: http://site.douban.com/204209/   ...

  9. Erlang C1500K长连接推送服务-性能

    Whatsapp已经使用Erlang在生产环境跑到96GB内存单机 3M长连接,参加:WhatsApp的Erlang世界.毕竟业务级别能达到Whatsapp那样极少,现在只有千万级,单机太多挂一台影响 ...

随机推荐

  1. Webpack+React+ES6开发模式入门指南

    React无疑是今年最火的前端框架,github上的star直逼30,000,基于React的React Native的star也直逼20,000.有了React,组件化似乎不再步履蹒跚,有了Reac ...

  2. 2000条你应知的WPF小姿势 基础篇<45-50 Visual Tree&Logic Tree 附带两个小工具>

    在正文开始之前需要介绍一个人:Sean Sexton. 来自明尼苏达双城的软件工程师.最为出色的是他维护了两个博客:2,000Things You Should Know About C# 和 2,0 ...

  3. Entity Framework 6 Recipes 2nd Edition(12-5)译 -> 自动删除相关联实体

    12-5. 自动删除相关联实体 问题 当一个实体被删除时,你想自动删除它相关联的实体 解决方案 假设你有一个表结构由一个course (科目), course 的classes (课程),以及enro ...

  4. Linux网络编程系列-常见疑惑

    1.并发TCP最大连接数 一个TCP连接有一个四元组唯一标识{local_ip, local_port, remote_ip, remote_port} client端建立连接请求时,通常让系统分配一 ...

  5. iOS 4s-6Plus屏幕自动适配及颜色转换为十六进制

    iOS各种屏幕自动适配及颜色转换为十六进制 ★★★XLJMatchScreen自动适配屏幕★★★ 支持pod导入 pod 'XLJScreenMatching', '~> 1.0.3' 如果发现 ...

  6. div里嵌套了img 底部会出现白边

    因为img默认是按基线(baseline)对齐的.对比一下图片和右边的p, q, y等字母,你会发现这三个字母的“小尾巴”和图片下方的空白一样高.下面这张图中的黑线就是那条基线. 要去掉空格可以使用v ...

  7. 【.net 深呼吸】连接Access数据库应注意的几点

    本地数据库可以有Y种选择,比如Sqlite.SQL Server Express.SQL Local DB.SQL Server CE.Access等,本文老周选用比较著名的Access本地数据库,在 ...

  8. Java正则速成秘籍(一)之招式篇

    导读 正则表达式是什么?有什么用? 正则表达式(Regular Expression)是一种文本规则,可以用来校验.查找.替换与规则匹配的文本. 又爱又恨的正则 正则表达式是一个强大的文本匹配工具,但 ...

  9. .NET 垃圾回收与内存泄漏

    > 前言相信大家一定听过,看过甚至遇到过内存泄漏.在 .NET 平台也一定知道有垃圾回收器,它可以让开发人员不必担心内存的释放问题,因为它会自定管理内存.但是在 .NET 平台下进行编程,绝对不 ...

  10. 学习EF之贪懒加载和延迟加载(2)

    通过昨天对EF贪婪加载和延迟加载的学习,不难发现,延迟加载还是很好用的,但是问题也就来了,有的时候我们只需要加载一个实体,不需要和他相关的外部实体,这时候我们来看看EF延迟加载时怎么作用的吧 打开pr ...