我想从序言中的现有列表中创建一个过滤列表
I want to make a filtered list out of a existing list in prolog
问题是;我有一个混合元素列表 [Y, donkey, horse, 30, father(max)]
。我想从中创建一个新列表,只包含原子。
我想写一个名为 atoms/2 的 Prolog 谓词,当在第一个参数位置提供一个列表时,将实例化在第二个参数位置提供的变量,其中包含出现在输入列表(包括任何可能的重复元素)。
像这样:
?- atoms([Y, donkey, horse, 30, father(max)], Result).
Result = [donkey, horse].
- 安装 SWI-Prolog。
- 开始吧。
- 在
?-
提示符下键入:edit(include/3).
并按 Enter。
- 当您看到
include/3
的库定义时惊叹不已。
- 将其用作谓词的起点。
- 思考开源的重要性。
或者,查看此答案:
由于大多数 Prolog 系统实现了 member/2
列表成员谓词以及标准 atom/1
和 findall/3
谓词,一个简单的可移植解决方案是:
atoms(List, Atoms) :-
findall(
Atom,
(member(Atom, List), atom(Atom)),
Atoms
).
调用示例:
| ?- atoms([Y, donkey, horse, 30, father(max)], Atoms).
Atoms = [donkey,horse]
yes
我假设这是为了完成作业,并且您的讲师希望您编写自己的代码,而不是使用内置的 member/2
和 findall/3
。
Prolog 有一个内置谓词 atom/1
,我们将使用它来识别原子。
而序言是一种递归语言。诀窍是学会递归思考。大多数递归问题可以分解为 1 或 2 个特殊情况,然后是更一般的递归情况。
所以...
我们有一个特例,空列表:
atoms( [] , [] ).
我们有两个一般的递归案例。一种是列表的头部(第一项)是一个原子的情况,这种情况我们将列表项添加到结果列表中并向下递归:
atoms( [X|Xs], [X|Atoms] ) :- atom(X), !, atoms(Xs,Atoms) .
other/last情况是当前列表项不是原子的情况,在这种情况下我们简单地丢弃列表项并向下递归。
atoms( [X|Xs], Atoms ) := \+atom(X), atoms(Xs,Atoms) .
把它们放在一起,你得到
atoms( [] , [] ) .
atoms( [X|Xs] , [X|Atoms] ) :- atom(X), atoms(Xs,Atoms) .
atoms( [X|Xs] , Atoms ) :- \+ atom(X), atoms(Xs,Atoms) .
请注意,这可以简化以消除冗余的原子性测试。将列表项作为原子的标识是确定性,也就是说,列表项不会不再是原子,我们再看一遍,所以我们可以使用 cut ( !
) 运算符修剪搜索树:
atoms( [] , [] ) .
atoms( [X|Xs] , [X|Atoms] ) :- atom(X), !, atoms(Xs,Atoms) .
atoms( [X|Xs] , Atoms ) :- atoms(Xs,Atoms) .
问题是;我有一个混合元素列表 [Y, donkey, horse, 30, father(max)]
。我想从中创建一个新列表,只包含原子。
我想写一个名为 atoms/2 的 Prolog 谓词,当在第一个参数位置提供一个列表时,将实例化在第二个参数位置提供的变量,其中包含出现在输入列表(包括任何可能的重复元素)。
像这样:
?- atoms([Y, donkey, horse, 30, father(max)], Result).
Result = [donkey, horse].
- 安装 SWI-Prolog。
- 开始吧。
- 在
?-
提示符下键入:edit(include/3).
并按 Enter。 - 当您看到
include/3
的库定义时惊叹不已。 - 将其用作谓词的起点。
- 思考开源的重要性。
或者,查看此答案:
由于大多数 Prolog 系统实现了 member/2
列表成员谓词以及标准 atom/1
和 findall/3
谓词,一个简单的可移植解决方案是:
atoms(List, Atoms) :-
findall(
Atom,
(member(Atom, List), atom(Atom)),
Atoms
).
调用示例:
| ?- atoms([Y, donkey, horse, 30, father(max)], Atoms).
Atoms = [donkey,horse]
yes
我假设这是为了完成作业,并且您的讲师希望您编写自己的代码,而不是使用内置的 member/2
和 findall/3
。
Prolog 有一个内置谓词 atom/1
,我们将使用它来识别原子。
而序言是一种递归语言。诀窍是学会递归思考。大多数递归问题可以分解为 1 或 2 个特殊情况,然后是更一般的递归情况。
所以...
我们有一个特例,空列表:
atoms( [] , [] ).
我们有两个一般的递归案例。一种是列表的头部(第一项)是一个原子的情况,这种情况我们将列表项添加到结果列表中并向下递归:
atoms( [X|Xs], [X|Atoms] ) :- atom(X), !, atoms(Xs,Atoms) .
other/last情况是当前列表项不是原子的情况,在这种情况下我们简单地丢弃列表项并向下递归。
atoms( [X|Xs], Atoms ) := \+atom(X), atoms(Xs,Atoms) .
把它们放在一起,你得到
atoms( [] , [] ) .
atoms( [X|Xs] , [X|Atoms] ) :- atom(X), atoms(Xs,Atoms) .
atoms( [X|Xs] , Atoms ) :- \+ atom(X), atoms(Xs,Atoms) .
请注意,这可以简化以消除冗余的原子性测试。将列表项作为原子的标识是确定性,也就是说,列表项不会不再是原子,我们再看一遍,所以我们可以使用 cut ( !
) 运算符修剪搜索树:
atoms( [] , [] ) .
atoms( [X|Xs] , [X|Atoms] ) :- atom(X), !, atoms(Xs,Atoms) .
atoms( [X|Xs] , Atoms ) :- atoms(Xs,Atoms) .