在列表中摆脱元组,erlang

时间:2015-02-21 03:30:42

标签: filter erlang

我想摆脱列表中的所有元组,例如。

我有类似的东西作为输入

test:stack({push, [{{mul,{plus,{num,2},{num,3}},{num,4}},[]}]}, []). 
%% note:  (returns wrong output because of the multiple tuples brackets)

如果我有这样的事情:

proj:stack({push, [mul,plus,{num,2},{num,3},{num,4}]}, []). 
%% this would return: 
%% [{push,{num,4}},{push,{num,3}},{push,{num,2}},
%%  {push,plus},{push,mul}] 
%% This is near to what I need.

我的代码是这样的:

stack({push, []}, StackList) -> StackList;
stack({push,[H|T]}, StackList) ->   
stack({push, T}, [{push,H} | StackList]). 

我想实现这样的目标:

{push, {num, 4}}, {push, {num, 3}}, 
{push, {num, 2}}, {add}, {mul}, {pop}, {ret}

我想过使用过滤器来实现这个目标,但也许是其他的东西?

2 个答案:

答案 0 :(得分:5)

评论太大了。 MEH ...

这看起来很像你正在尝试构建一个堆栈机器,在这种情况下可能是一个计算器。我强烈建议你看一下good RPN example walkthrough in LYSE。它没有处理这种特定的语法,但它演示了如何使用函数头中的匹配来累积一组消耗的操作。

您必须决定的是元素的语义。现在你有元组元组的元组 - 这不是元组的用途。形式为{Operation, Operand}{Operation, Operand1, Operand2}的元组非常有意义 - 它们在语义上是截然不同的 - 但{OperationZ, {OperationX, Operand}, {OperationQ, Operand1, Operand2}}形式的元组没有任何意义,因为每个元素都是元组应该具有不同的含义。在这里,您刚刚嵌套了一堆元组,这些元组具有自己的意义到一个更大的元组中,这个元组本身现在只是混淆了。

解决方案是使用列表,而不是元组。如果你更进一步,而不是使用" push / pop"作为他们自己的操作,考虑完全展开你的元组,并根据系统的基础规则集,按照自己的条件处理列表中的每个元素。因此,不要在{push, 4}中包装值,而只提供4,因为隐式操作始终是推送(或弹出,取决于您的观点...更好,实际上,免除此概念,因为堆栈已作为输入存在。

从上面的例子中提取:

[{push,{num,4}},{push,{num,3}},{push,{num,2}},{push,plus},{push,mul}]

会变成

[4, 3, 2, add, mul]

这可以解释为没有含糊不清,我们不需要混淆pushnum标识符:

-module(rpn).
-export([calc/1]).

calc(List) ->
    [Res] = lists:foldl(fun calc/2, [], List),
    Res.

calc(mul, [N1, N2 | Stack]) -> [N1 * N2 | Stack];
calc(add, [N1, N2 | Stack]) -> [N1 + N2 | Stack];
calc(X, Stack) -> [X | Stack].

希望这说明的不仅仅是混淆。请记住,可以将所有内容包含在元组中并匹配元组标记和值变量,但这不是必需的。上面的代码根本没有类型检查,但是如果你向元素添加标签(但嵌套元组),那么你可以使用这些标签作为类型标记的形式(如果你立即崩溃)收到错误的标签,或跳过任何意外的标签) - 但这意味着您需要在语义上进一步备份:

[{num, 4}, {num, 3}, {num, 2}, {op, add}, {op, mul}]

现在玩这个有点让代码变得复杂,以至于如果输入不好,我真的只是使用防护并提前崩溃。

答案 1 :(得分:0)

以下是您拥有的代码:

lists:filter(fun(E) -> E /= {} end, list1)

这不会过滤列表中的所有元组。这只过滤掉等于空元组{}的列表元素。如果你想要一个从列表中过滤元组的函数,你应该使用not和is_tuple / 1 BIF替换lambda表达式中的E / = {}谓词:

not is_tuple(E)

我对你最初的问题也有些困惑。你说

list1 = [{1},{2},{3}]我想要它作为list1 = [1,2,3]

这让我觉得您想要映射列表并将列表中的每个元素元组转换为其内容。如果这是您想要的行为,请使用map / 2 BIF或列表推导。

[ E || {E} <- list1]

对于list1中的每个单个元素元组,此表达式被读作&#34;生成一个新的列表,其元素是这些元组的内容。&#34;

希望这会有所帮助。享受Erlang。