在Prolog DCG中使用列表

3
我正在尝试将一个Prolog谓词转换为DCG代码。即使我熟悉语法语言,我仍然有些困难理解DCG如何处理列表以及我应该如何使用它。
实际上,这是我的谓词:
cleanList([], []).
cleanList([H|L], [H|LL]) :-
    number(H),
    cleanList(L, LL),
    !.
cleanList([_|L], LL) :-
    cleanList(L, LL).

这是一个简单的谓词,它会删除非数字元素。我想要使用DCG编写相同的行为。
我尝试了下面的代码(显然不起作用):
cleanList([]) --> [].
cleanList([H]) --> {number(H)}.
cleanList([H|T]) --> [H|T], {number(H)}, cleanList(T).

能否向我解释一下出了什么问题或者缺少了什么吗?
谢谢!

一个大问题是 ... --> [H|T], ...。你想让 DCG 读取一个序列,而 [H|T] 具有任意长度。不确定为什么在该术语中包括了 T。你对 cleanList(T) 的递归调用已经扫描了输入中的 T - lurker
哦,我明白了!谢谢你的回复,我之前不理解DCG如何递归地读取序列,现在没问题了。 - Naeoth
1个回答

2
DCG符号的目的正是为了隐藏或更好地说,使令牌列表成为隐式的。因此,您的代码应该如下所示:
cleanList([]) --> [].
cleanList([H|T]) --> [H], {number(H)}, cleanList(T).
cleanList(L) --> [H], {\+number(H)}, cleanList(L).

可以更加高效的方法:
cleanList([]) --> [].
cleanList([H|T]) --> [H], {number(H)}, !, cleanList(T).
cleanList(L) --> [_], cleanList(L).

一个风格的注意事项:Prolog程序员更喜欢避免驼峰命名法:)
clean_list([]) --> [].
etc...

此外,我更喜欢更紧凑的代码:
clean_list([]) --> [].
clean_list(R) --> [H], {number(H) -> R = [H|T] ; R = T}, clean_list(T).

我知道我已经接近答案了,感谢您的精确和建议! - Naeoth
不好意思,这个问题可能很明显,但是如何调用上面给出的 clean_list/3 函数呢?如果我想将 [1, 2, c, d, 5] 清理成 [1, 2, 5],我应该如何调用上面给出的定义来实现呢? - Mike Harris
1
@MikeHarris:有一个ISO标准接口,phrase/2?- phrase(clean_list(Clean),[1, 2, c, d, 5]) - CapelliC

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接