首页 > 解决方案 > Core Erlang 的 `letrec` 是干什么用的?

问题描述

Core Erlang 的letrec用途是什么?

Richard Carlsson 在“Core Erlang 简介”中写道:

此外letrec,表达式允许局部(递归)函数定义,ERLANG 本身没有,但在转换中通常很有用。

letrec 对哪些转换有用?

从 Erlang 翻译时是否erlc实际生成?letrec还是letrec只有在从非 Erlang 源语言翻译时才会生成 s?

标签: erlang

解决方案


如今,列表推导式被翻译成 letrecs(在 Core Erlang 中可用),而 letrecs 又被翻译成普通的递归函数。

请注意,“Nowadays”是 2010 年。此外,还有一些在EEP 52 中使用的示例: Allow key and size expressions in map and binary matching

在 OTP 23 中,段大小表达式中使用的所有变量必须已经绑定在封闭环境中。前面的示例必须使用嵌套案例重写如下:

   'foo'/1 =
       fun (_0) ->
             case _0 of
                 <#{#<Sz>(16,1,'integer',['unsigned'|['big']]),
                  #<_2>('all',1,'binary',['unsigned'|['big']])}#> when 'true' ->
                     case _2 of
                        <#{#<X>(Sz,1,'integer',['unsigned'|['big']])}#> when 'true' ->
                            X
                        <_3> when 'true' ->
                            %% Raise function_clause exception.
                            .
                            .
                            .
                       end
                  <_4> when 'true' ->
                       %% Raise function_clause exception.
                       .
                       .
                       .
                 end

但是,从示例中可以看出,引发function_clause 异常的代码已重复。在这个简单的示例中,代码重复没什么大不了的,但它会出现在二进制匹配子句后跟许多其他子句的函数中。为了避免代码重复,我们必须使用letrecwithletrec_goto注解:

   'foo'/1 =
       fun (_0) ->
           ( letrec
                 'label^0'/0 =
                     fun () ->
                           case _0 of
                             <_1> when 'true' ->
                                   %% Raise function_clause exception.
                                   .
                                   .
                                   .
                           end
             in  case _0 of
                   <#{#<Sz>(16,1,'integer',['unsigned'|['big']]),
                      #<_2>('all',1,'binary',['unsigned'|['big']])}#> when 'true' ->
                       case _2 of
                         <#{#<X>(Sz,1,'integer',['unsigned'|['big']])}#> when 'true' ->
                             X
                         <_3> when 'true' ->
                               apply 'label^0'/0()
                       end
                   <_4> when 'true' ->
                         apply 'label^0'/0()
                 end
             -| ['letrec_goto'] )

推荐阅读