如何处理 [a,b|c] 格式列表?
How to deal with [a,b|c] format lists?
我为 Clojure 语言的子集创建了一个简单的解析器。出于某种原因,它 returns 我是一个 [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),
!.
首先,使用可读性更好的语法,方法是在代码前面设置以下指令:
:- set_prolog_flag(double_quotes, chars).
现在您可以编写更紧凑的 "}"
来代替 ['}']
,而不是 ['\s']
标准的 " "
。或者 specsymbol(+) --> "+".
代替。
其次,像这样定义 letter//1
和 anychar//1
:
letter(L) --> [L], {char_type(L,alpha)}.
anychar(A) --> [A], {dif(A, '\"')}.
有了这个,您就可以开始调试了,最好使用较小的测试用例。
还要注意Prolog有一个顶层(prolog-toplevel),所以根本不需要定义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
应该读作:
expressions([S]) --> expression(S).
expressions([S|Ss]) -->
{Ss = [_|_]}, % redundant goal for termination
expression(S), mydelimiter, expressions(Ss).
注意还有
?- phrase(expression(T),"(inc,,,x)").
成功,我不确定这是不是故意的。
我为 Clojure 语言的子集创建了一个简单的解析器。出于某种原因,它 returns 我是一个 [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),
!.
首先,使用可读性更好的语法,方法是在代码前面设置以下指令:
:- set_prolog_flag(double_quotes, chars).
现在您可以编写更紧凑的 "}"
来代替 ['}']
,而不是 ['\s']
标准的 " "
。或者 specsymbol(+) --> "+".
代替。
其次,像这样定义 letter//1
和 anychar//1
:
letter(L) --> [L], {char_type(L,alpha)}.
anychar(A) --> [A], {dif(A, '\"')}.
有了这个,您就可以开始调试了,最好使用较小的测试用例。
还要注意Prolog有一个顶层(prolog-toplevel),所以根本不需要定义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
应该读作:
expressions([S]) --> expression(S). expressions([S|Ss]) --> {Ss = [_|_]}, % redundant goal for termination expression(S), mydelimiter, expressions(Ss).
注意还有
?- phrase(expression(T),"(inc,,,x)").
成功,我不确定这是不是故意的。