Core Erlang 的 `letrec` 有什么用?

What is Core Erlang's `letrec` for?

Core Erlang 的 letrec 有什么用?

Richard Carlsson 在 "Introduction to Core Erlang" 中写道:

Furthermore letrec expressions allow local (recursive) function definitions, which ERLANG itself does not have, but which are often useful in transformations.

letrec 对哪些转换有用?

从 Erlang 翻译时 erlc 是否实际生成 letrec?或者只有从非 Erlang 源语言翻译时才会生成 letrecs?

Nowadays, list comprehensions are translated to letrecs (which are available in Core Erlang), and the letrecs are in turn translated to ordinary recursive functions.

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

In OTP 23, all variables used in a segment size expression must be already bound in the enclosing environment. The previous example must be rewritten like this using nested cases:

   '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

However, as can be seen from the example, the code for raising the function_clause exception has been duplicated. The code duplication is no big deal in this simple example, but it would be in a function where the binary matching clause was followed by many other clauses. To avoid the code duplication, we must use letrec with the letrec_goto annotation:

   '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'] )