34

我想知道通常如何实现模式匹配。例如,在 Erlang 中,您认为它是在字节码级别实现的(它有一个字节码以便它有效地完成)还是由编译器生成为一系列指令(一系列字节码)?

这是一个非常有用的东西,我只需要将它放入我正在构建的玩具语言中。

4

4 回答 4

35

Simon Peyton Jones在“函数式编程语言的实现”中对编译模式匹配进行了很好的描述。这本书有点旧,但非常好。除其他外,它还包含对编译列表推导的描述。

Erlang 编译器使用书中的这两种算法。

于 2009-03-13T14:11:19.013 回答
20

你可以看看如果编译一些代码会发生什么

-module(match).
-export([match/1]).
match(X) -> {a,Y} = X.

当你想看看看起来像核心

> c(match, to_core).

或者

$ erlc +to_core match.erl

结果是

module 'match' ['match'/1,
                'module_info'/0,
                'module_info'/1]
    attributes []
'match'/1 =
    %% Line 3
    fun (_cor0) ->
        case _cor0 of
          <{'a',Y}> when 'true' ->
              _cor0
          ( <_cor1> when 'true' ->
                primop 'match_fail'
                    ({'badmatch',_cor1})
            -| ['compiler_generated'] )
        end
'module_info'/0 =
    fun () ->
        call 'erlang':'get_module_info'
            ('match')
'module_info'/1 =
    fun (_cor0) ->
        call 'erlang':'get_module_info'
            ('match', _cor0)

如果您想查看梁的 asm 代码,您可以这样做

> c(match, 'S').

或者

$ erlc -S match.erl

和结果

{module, match}.  %% version = 0

{exports, [{match,1},{module_info,0},{module_info,1}]}.

{attributes, []}.

{labels, 8}.


{function, match, 1, 2}.
  {label,1}.
    {func_info,{atom,match},{atom,match},1}.
  {label,2}.
    {test,is_tuple,{f,3},[{x,0}]}.
    {test,test_arity,{f,3},[{x,0},2]}.
    {get_tuple_element,{x,0},0,{x,1}}.
    {test,is_eq_exact,{f,3},[{x,1},{atom,a}]}.
    return.
  {label,3}.
    {badmatch,{x,0}}.


{function, module_info, 0, 5}.
  {label,4}.
    {func_info,{atom,match},{atom,module_info},0}.
  {label,5}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,1,{extfunc,erlang,get_module_info,1}}.


{function, module_info, 1, 7}.
  {label,6}.
    {func_info,{atom,match},{atom,module_info},1}.
  {label,7}.
    {move,{x,0},{x,1}}.
    {move,{atom,match},{x,0}}.
    {call_ext_only,2,{extfunc,erlang,get_module_info,2}}.

如您所见{test,is_tuple,...{test,test_arity,...和是指示如何在光束中执行此匹配{get_tuple_element,...并将{test,is_eq_exact,...其直接转换为光束的字节码。

Erlang 编译器是在 Erlang 本身中实现的,您可以在compile模块的源代码中查看编译的每个阶段,并在依赖模块中查看详细信息。

于 2009-02-25T16:27:23.573 回答
14

如果你想构建自己的模式匹配器,Scott 和 Ramsey一篇论文以及 Luc Maranget的一篇论文都描述了如何将模式编译为高效的决策树(也称为嵌套 switch 语句)。

于 2009-02-26T03:39:21.977 回答
2

我可以建议的最好的事情是编译一些测试函数并查看生成的代码。

erlc -S test.erl

生成具有相当可读性的 test.S。

为了回答这个问题,模式匹配是通过更原始的操作以一种有效的方式建立起来的。这是匹配 {X, [H|T]} 的函数子句的部分代码。

{test,is_tuple,{f,1},[{x,0}]}.
{test,test_arity,{f,1},[{x,0},2]}.
{get_tuple_element,{x,0},0,{x,1}}.
{get_tuple_element,{x,0},1,{x,2}}.
{test,is_nonempty_list,{f,4},[{x,2}]}.
于 2009-02-25T16:23:10.870 回答