【问题标题】:How to deal with [a,b|c] format lists?如何处理 [a,b|c] 格式列表?
【发布时间】:2022-08-11 18:06:53
【问题描述】:

我为 Clojure 语言的子集创建了一个简单的解析器。出于某种原因,它返回格式为 [a,b,c|d] 的列表,而不是格式 [a,b,c,d] 的列表。 Morover member(X, List) 不能正确使用这种格式的列表,即

member(X, [a,b,c|d]).
X = a ;
X = b ;
X = c.

问题是我应该如何改进我的代码来解决这个问题并以通常的格式获取列表?或者也许有一种方法可以转换 [a,b,c|d] -> [a,b,c,d] ?

你可以打电话给例如

main.
[(concat x) (lambda x (inc (inc x)))]

并得到:

expr([expr([expr(at(id([c,o,n,c,a,t])))|expr(at(id([x])))])|expr([expr(at(id([l,a,m,b,d,a]))),expr(at(id([x])))|expr([expr(at(id([i,n,c])))|expr([expr(at(id([i,n,c])))|expr(at(id([x])))])])])])

代码:

mydelimiter --> delimiter.
mydelimiter --> delimiter, mydelimiter.
delimiter --> [\',\'].
delimiter --> [\'\\n\'].
delimiter --> [\'\\t\'].
delimiter --> [\'\\s\'].

specsymbol(\'+\') --> [\'+\'].
specsymbol(\'-\') --> [\'-\'].
specsymbol(\'>\') --> [\'>\'].
specsymbol(\'<\') --> [\'<\'].
specsymbol(\'=\') --> [\'=\'].
specsymbol(\'*\') --> [\'*\'].
specsymbol(\'_\') --> [\'_\'].

snum(0) --> [\'0\'].
snum(1) --> [\'1\'].
snum(2) --> [\'2\'].
snum(3) --> [\'3\'].
snum(4) --> [\'4\'].
snum(5) --> [\'5\'].
snum(6) --> [\'6\'].
snum(7) --> [\'7\'].
snum(8) --> [\'8\'].
snum(9) --> [\'9\'].
numb([A]) --> snum(A).
numb([A|B]) --> snum(A), numb(B).
mynumber(num(X)) --> numb(X).

mystring(str([])) --> quotesymbol, quotesymbol.
mystring(str(S)) --> quotesymbol, anychars(S), quotesymbol.
quotesymbol --> [\'\\\"\'].
anychar(A) --> [A], {A \\== \'\\\"\'}.
anychars([A]) --> anychar(A).
anychars([A|B]) --> anychar(A), anychars(B).

identifier(id(I)) --> id_start_spec(I); id_start_letter(I).
letter(L) --> [L], {is_alpha(L)}.
id_start_letter([L]) --> letter(L).
id_start_letter([L|I]) --> letter(L), ids_l(I).
ids_l([I]) --> letter(I); snum(I); specsymbol(I).
ids_l([I|Is]) --> (letter(I); snum(I); specsymbol(I)), ids_l(Is).
id_start_spec([S]) --> specsymbol(S).
id_start_spec([S|I]) --> specsymbol(S), ids_s(I).
ids_s([I]) --> snum(I); specsymbol(I).
ids_s([I|Is]) --> (snum(I); specsymbol(I)), ids_s(Is).

keyword(kw([C|K])) --> mycolonsymbol(C), id_start_letter(K).
mycolonsymbol(\':\') --> [\':\'].

myatom(at(A)) --> mynumber(A); mystring(A); identifier(A); keyword(A).

expression(expr(S)) --> myatom(S).
expression(expr(S)) --> r_br_expression(S).
expression(expr(S)) --> s_br_expression(S).
expression(expr(S)) --> f_br_expression(S).
r_br_expression(S) --> r_openbracketsymbol, expressions(S), r_closedbracketsymbol.
expressions(S) --> expression(S).
expressions([S|SS]) --> expression(S), mydelimiter, expressions(SS).
r_openbracketsymbol --> [\'(\'].
r_closedbracketsymbol --> [\')\'].
s_br_expression(S) --> s_openbracketsymbol, expressions(S), s_closedbracketsymbol.
s_openbracketsymbol --> [\'[\'].
s_closedbracketsymbol --> [\']\'].
f_br_expression(S) --> f_openbracketsymbol, expressions(S), f_closedbracketsymbol.
f_openbracketsymbol --> [\'{\'].
f_closedbracketsymbol --> [\'}\'].

main :-
    read_string(user_input, \"\\n\", \"\", _, StrIn),
    atom_chars(StrIn, L),
    phrase(expression(T), L),
    writeln(T),
    !.
  • 应该是(遵循头尾符号):?- member(X, [a,b,c|[d]])。
  • @brebs是的,我忘了正确的部分必须是一个列表,你不能只设置尾部的所有元素

标签: prolog dcg


【解决方案1】:

首先,使用更好的可读语法,通过在代码前面设置以下指令:

:- set_prolog_flag(double_quotes, chars).

现在你可以用更紧凑的"}"代替['}'],而不是标准的['\s']['\s']。或者specsymbol(+) --&gt; "+".

其次,像这样定义letter//1anychar//1

letter(L) --> [L], {char_type(L,alpha)}.

anychar(A) --> [A], {dif(A, '\"')}.

有了这个,您可以开始调试,最好使用较小的测试用例。

另请注意,Prolog 有一个顶层(),所以根本不需要定义main。相反,您可以直接键入查询,或者更好的是,首先考虑一个更简单的情况:

?- phrase(expression(T),"(inc x)").
   T = expr([expr(at(id("inc")))|expr(at(id("x")))]).
?- phrase(expression(T),"(x)").
   T = expr(expr(at(id("x")))).

因此,在第一种情况下,有一个部分列表的奇数实例,而在第二种情况下,根本没有列表。相反,两者都应该是(格式良好的)列表。罪魁祸首是expressions//1,应该改为:

表达式([S]) --> 表达式(S)。
表达式([S|Ss])-->{SS = [_|_]}, % 终止的冗余目标
   表达式(S),mydelimiter,表达式(Ss)。

请注意,还

?- phrase(expression(T),"(inc,,,x)").

成功了,我不确定这是不是有意的。

【讨论】:

    猜你喜欢
    • 2015-06-12
    • 1970-01-01
    • 1970-01-01
    • 2020-07-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多