【问题标题】:Why does pattern matching records in Erlang throw error为什么 Erlang 中的模式匹配记录会抛出错误
【发布时间】:2019-12-13 06:33:54
【问题描述】:

您好,我正在尝试使用 Erlang 中的记录语法将变量绑定到封闭记录及其字段之一,但我不断收到此错误:

d:/Erlang/AeRlang/rec.erl:19: 之前的语法错误:子

d:/Erlang/AeRlang/rec.erl:17: 函数 isMale/1 未定义

d:/Erlang/AeRlang/rec.erl:17: 警告:函数 maleChildren/1 是 未使用

-module(rec).
-export([makeFam/0]).

-record(man,{name,
             age,
             children=[]}).
-record(child,{
    name,
    age,
    sex
}).

makeFam()->
    #man{name="Adrian",
         age=33,
         children=[#child{name="Daniel",age=33,sex="Male"},
                   #child{name="Chris" ,sex="Male"},
                   #child{name="Anne",age=33,sex="Female"}]
        }.


fatherAndSons(Man#man{children=Ch})->{Man,[Elem|| Elem<-Ch,isMale(Elem)]}.
    
isMale(C#child{_,_,Y})->
    case Y of 
        "Male"->true;
         _ ->false
    end.

我的isMale 方法有什么问题。我将封闭结构#child 绑定到变量C,并且我也在对其字段进行模式匹配。有什么问题?

P.S:这是否与在isMale 方法中我没有指定绑定变量Y 的字段的名称有关?

【问题讨论】:

    标签: erlang pattern-matching record


    【解决方案1】:

    在您的child record 中获取sex 的方式存在一些错误。您可以更改您的函数fatherAndSons/1isMale/1,如下所示:

    fatherAndSons(Man#man{children=Ch})->{Man,[Elem|| Elem<-Ch,isMale(Elem) == true]}.
    
    isMale(C)->
        case C#child.sex of 
            "Male"->true;
             _ ->false
        end.
    

    或者只是删除您的isMale/1 和列表理解中的模式匹配:

    fatherAndSons(Man#man{children=Ch})->
        {Man, [Elem || Elem <-Ch, Elem#child.sex == "Male"]}.
    

    【讨论】:

    • 但是为什么会出现问题,因为我直接在isMale 参数上绑定变量,然后在case 子句中绑定时对其进行模式匹配。出了什么问题?
    • case 子句中的模式匹配没有错。在记录child 中获取变量Y 的方式是错误的。只能将isMale(C#child{_,_,Y})-&gt;这一行改成isMale(#child{sex = Y})-&gt;
    【解决方案2】:

    对于fatherAndSons/1isMale/1 函数,您使用错误的语法将记录匹配为函数参数。以下是一些更正的版本:

    fatherAndSons(Man=#man{children=Ch}) -> {Man, [Elem || Elem <- Ch, isMale(Elem)]}.
    
    isMale(#child{sex="Male"})-> true;
    isMale(_) -> false.
    

    fatherAndSons/1 的函数头中,我们基本上是在说“Man 应该是一个#man 记录,我们将绑定到children 字段的Ch”。 = 运算符是匹配的,但您在 Man 绑定中缺少它。

    对于isMale/1,我使用了两个子句,其中第一个子句匹配所有#child 记录,其sex 字段匹配字符串"Male",第二个子句匹配其他任何内容。如果您想将第二个子句限制为仅匹配 #child 记录,您可以改用:

    isMale(#child{sex="Male"})-> true;
    isMale(#child{}) -> false.
    

    无论哪种方式,请注意无需将记录绑定到函数头中的变量isMale/1,因为您不需要在函数体中进行绑定。

    【讨论】:

    • 但是我没有使用=,因为这是在模式匹配整个结构时出现在Learn you a Erlang for great good 中的方式,尽管不是作为函数参数而是在方法内部。 (查看方法repairman
    • 在您引用的repairman 函数中,Details = Rob#robot.details 行的意思是“将Details 绑定到details 字段的值Rob,这是一个实例#robot 记录。”换句话说,在这种情况下,Rob 已经绑定到 #robot 记录,这与您尝试将 Man 绑定到函数头中的 #man 记录不同。
    • 感谢您的详尽解释!
    猜你喜欢
    • 2018-01-08
    • 2013-06-25
    • 2015-01-12
    • 1970-01-01
    • 2019-09-03
    • 2016-04-29
    • 2011-11-10
    • 1970-01-01
    • 2019-09-24
    相关资源
    最近更新 更多