Functional programming 接收时记录列表的Erlang模式匹配

Functional programming 接收时记录列表的Erlang模式匹配,functional-programming,erlang,pattern-matching,Functional Programming,Erlang,Pattern Matching,我正在尝试为我的应用程序中需要在不同时间等待多个更新的部分创建通用接收。 这是它不工作的原型 receive_info([])->[]; receive_info([RequiredInfo|RestRequiredInfos]) -> receive RequiredInfo -> [ RequiredInfo | receie_info(RestRequiredInfos)]; end. 它被称为 [UserInfo, ContextInfo] = rec

我正在尝试为我的应用程序中需要在不同时间等待多个更新的部分创建通用接收。
这是它不工作的原型

receive_info([])->[];
receive_info([RequiredInfo|RestRequiredInfos]) ->
  receive
    RequiredInfo -> [ RequiredInfo | receie_info(RestRequiredInfos)];
  end.
它被称为

[UserInfo, ContextInfo] = receive_info([#userinfo{},#contextinfo{}]),
因此,我试图发送一个它应该匹配的记录类型列表,我希望收到一个记录列表。
不确定这是否可行,因为记录将其字段设置为未定义,并且模式匹配不起作用,例如:

Trying to receive {user_info,undefined}
Other clause: instead {user_info,12} received
编辑:
由于@Adam Lindberg提供的版本对我不起作用,我采用了一种类似的方法,结果是:

receive_infos([]) -> [];
receive_infos([Rec|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= Rec -> 
        [ Record | receive_infos(Records)]
end.

有几件事。您正在尝试将RequiredInfo(默认记录数据)与RequiredInfo(作为消息发送的已填充记录数据)匹配。因此,您只希望获得您已经拥有的数据,我认为这些数据可能不是您想要的。你在接收信息时也有一些拼写错误

如果我想用接收到的填充记录填充默认记录列表,并且必须接收所有记录,否则所有记录都会失败,我可能会这样做

fill_records(List)   -> fill_records(List,length(List)).
fill_records(List,0) -> List;
fill_records(List,N) ->
    receive Rec -> fill_records(lists:keyreplace(element(1,Rec),1,List,Rec),N-1)
    after 5000 -> {error,timeout} end.
根据周围系统的不同,您应该通过防止接收相同记录类型或不需要的记录类型的多个实例来确保这一点


当然,您也可以创建一个接收循环,在该循环中只定义预期的消息数量,或者查看gen_fsm或gen_server及其内部状态和消息处理

有几件事。您正在尝试将RequiredInfo(默认记录数据)与RequiredInfo(作为消息发送的已填充记录数据)匹配。因此,您只希望获得您已经拥有的数据,我认为这些数据可能不是您想要的。你在接收信息时也有一些拼写错误

如果我想用接收到的填充记录填充默认记录列表,并且必须接收所有记录,否则所有记录都会失败,我可能会这样做

fill_records(List)   -> fill_records(List,length(List)).
fill_records(List,0) -> List;
fill_records(List,N) ->
    receive Rec -> fill_records(lists:keyreplace(element(1,Rec),1,List,Rec),N-1)
    after 5000 -> {error,timeout} end.
根据周围系统的不同,您应该通过防止接收相同记录类型或不需要的记录类型的多个实例来确保这一点

当然,您也可以创建一个接收循环,在该循环中只定义预期的消息数量,或者查看gen_fsm或gen_server及其内部状态和消息处理

如果您将其重写为:

receive_info([]) -> [];
receive_info([Rec|Records]) ->
    receive
        Msg when is_record(Msg, Rec) ->
            [Msg|receive_info(Records)];
    end.
并称之为:

receive_info([userinfo, contextinfo])
它将执行您想要的操作。

如果您将其重写为:

receive_info([]) -> [];
receive_info([Rec|Records]) ->
    receive
        Msg when is_record(Msg, Rec) ->
            [Msg|receive_info(Records)];
    end.
并称之为:

receive_info([userinfo, contextinfo])

它将满足您的要求。

我认为您的最后一个答案是正确的,但您可以再添加一次检查,以确保您获得的记录大小正确:

receive_infos([]) -> [];
receive_infos([Rec|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= element(1, Rec), size(Record) =:= size(Rec) -> 
        [ Record | receive_infos(Records)]
end.
因为大小和第一个元素原子是记录的全部,这大概和你要做的一样好

或者更直截了当地接受这两个论点:

receive_infos([]) -> [];
receive_infos([{Name, Size}|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= Name, size(Record) =:= Size -> 
        [ Record | receive_infos(Records)]
end.
并称之为

receive_infos([{foo, record_info(size, foo)} | etc. ])

我认为您的最后一个答案是正确的,但您可以再添加一次检查,以确保获得正确大小的记录:

receive_infos([]) -> [];
receive_infos([Rec|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= element(1, Rec), size(Record) =:= size(Rec) -> 
        [ Record | receive_infos(Records)]
end.
因为大小和第一个元素原子是记录的全部,这大概和你要做的一样好

或者更直截了当地接受这两个论点:

receive_infos([]) -> [];
receive_infos([{Name, Size}|Records]) ->
receive
    %% Guard expression that compares first element in record with supplied record tag
    Record when element(1, Record) =:= Name, size(Record) =:= Size -> 
        [ Record | receive_infos(Records)]
end.
并称之为

receive_infos([{foo, record_info(size, foo)} | etc. ])

是的,我现在明白了,我不能只是通过列表和参数传递模式匹配表达式,然后使用它们进行接收模式匹配。现在,您要做的是将接收到的记录原子与列表中将记录视为元组的记录原子进行比较,不是吗?虽然看起来不是很像erlang Way,但它看起来应该可以工作。记录在内部是一个元组,其中记录名是第一个元素,不能定义两个名称相同但字段数不同的记录。据我所知,利用这一点并不罕见。:)你可以用is_记录解决方案来代替它,但缺点是你必须按顺序获取记录,并缓冲任何无序消息。是的,我现在了解到,我不能只通过列表和参数传递模式匹配表达式,然后使用它们来接收模式匹配。现在,您要做的是将接收到的记录原子与列表中将记录视为元组的记录原子进行比较,不是吗?虽然看起来不是很像erlang Way,但它看起来应该可以工作。记录在内部是一个元组,其中记录名是第一个元素,不能定义两个名称相同但字段数不同的记录。据我所知,利用这一点并不罕见。:)您可以用is_记录解决方案来代替它,但缺点是您必须按顺序获取记录并缓冲任何无序消息。这样做不是更好:接收{Rec,{u}和模式匹配元组标记,而不是使用is_记录?@Arkaitz{Rec,{u}仅匹配大小为2的元组,该元组与只有1个字段的记录相同。
when is_record(Msg,Rec)
是非法的保护表达式。我认为
is\u record
只能用于带有文字原子的防护,比如
when is\u record(Msg,user\u info)
我没有测试过这一点,但引用了文档:“但是,如果RecordTag不是文字原子,那么将调用is\u record/2 BIF,并且不会验证元组的大小。”@Arkaitz:您不应该使用内部记录表示,它被认为是不好的形式,因为当记录更改时,它更容易出现错误。这样做不是更好:接收{Rec,{u}和模式匹配元组标记,而不是使用is_record?@Arkaitz{Rec,{u}仅匹配大小为2的元组,该元组与只有1个字段的记录相同。
when is_record(Msg,Rec)
是非法的保护表达式。我认为
is\u-record
只能用于带有文字原子的防护,比如
when is\u-record(Msg,user\u-info)
我没有测试过这一点,但引用了文档:“但是,如果RecordTag不是文字原子,那么is\u-record/2 BIF w