按类型将列表分为两个单独的列表

时间:2016-07-27 08:23:34

标签: list prolog

我仍然是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.

1 个答案:

答案 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).

最后,您确实不需要isIntegerisFloat。在确认类型后,他们只会对值进行不必要的“复制”。您只需要测试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).