我仍然是Prolog的新手,我在涉及列表的练习中遇到了困难:给定一个任意数据列表,将列表分成两个列表 - 一个包含整数值,另一个包含实数值,然后忽略原始列表中的任何其他项目。
到目前为止,我已经写了以下内容:
isInteger(I, IntegerListHead):-
integer(I),
IntegerListHead is I.
isFloat(F, FloatListHead):-
float(F),
FloatListHead is F.
splitList([]).
splitList([H|T], [IntHead|IntList],[FloatHead|FloatList]):-
isInteger(H, IntHead),
isFloat(H, FloatHead),
splitList(T, IntList, FloatList).
但是,我不确定为什么会出现某些错误:
?- splitList([1, 2.5, 6, 7.0, -1, -0.5], I, F).
ERROR: toplevel: Undefined procedure: splitList/3 (DWIM could not correct goal)
这个错误的常见嫌疑人似乎并非如此,但也许我错过了什么?
编辑:当我重新加载文件并再次运行时,我得到以下内容:
?- splitList([1, 2.5, 6, 7.0, -1, -0.5], I, F).
false.
答案 0 :(得分:1)
您的基本情况需要更完整。它定义了统一列表为空时拆分列表的外观。所以基本情况应该是:
splitList([], [], []). % Split lists are empty iff the unified list is empty
你的recursive子句尝试一次完成所有操作,但是在列表的头部进行整数与浮点测试的结合,导致必然的错误条件。换句话说,仅当H
既是float又是整数时,以下情况才成立:
isInteger(H, IntHead),
isFloat(H, FloatHead)
您可以使用其他子句将其拆分。结果谓词如下所示:
splitList([], [], []).
splitList([H|T], [IntHead|IntList], FloatList):-
isInteger(H, IntHead),
splitList(T, IntList, FloatList).
splitList([H|T], IntList, [FloatHead|FloatList]):-
isFloat(H, FloatHead),
splitList(T, IntList, FloatList).
最后,您确实不需要isInteger
或isFloat
。在确认类型后,他们只会对值进行不必要的“复制”。您只需要测试H
:
splitList([], [], []).
splitList([H|T], [H|IntList], FloatList):-
integer(H),
splitList(T, IntList, FloatList).
splitList([H|T], IntList, [H|FloatList]):-
float(H),
splitList(T, IntList, FloatList).
<小时/> 正如@CapelliC指出的那样,如果您的列表中包含非数字,这将失败。您可以采用以下方法以获得更多通用性,这将跳过非数字元素。可以轻松修改它以将非数字元素保留在单独的列表中。
splitList([], [], []).
splitList([H|T], IntList, FloatList):-
( integer(H)
-> IntList = [H|Ints],
FloatList = Floats
; float(H)
-> IntList = Ints,
FloatList = [H|Floats]
; IntList = Ints,
FloatList = Floats
),
splitList(T, Ints, Floats).