我开始为即将到来的考试学习,但我仍然坚持一个琐碎的prolog练习题,这不是一个好兆头lol。
这应该很容易,但由于某些原因我现在无法弄明白。
任务是简单地计算prolog中Int列表中的奇数个数。 我在哈斯克尔很容易做到,但我的序言太可怕了。有人能告诉我一个简单的方法,并简要解释你做了什么吗?
到目前为止,我有:
odd(X):- 1 is X mod 2.
countOdds([],0).
countOdds(X|Xs],Y):-
?????
答案 0 :(得分:5)
你对odd / 1的定义很好。
空列表的事实也没问题。
在递归子句中,您需要区分奇数和偶数。如果数字是奇数,则应增加计数器:
countOdds([X|Xs],Y1) :- odd(X), countOdds(Xs,Y), Y1 is Y+1.
如果数字不是奇数(=偶数),则不应增加计数器。
countOdds([X|Xs],Y) :- \+ odd(X), countOdds(Xs,Y).
其中\+
表示否定为失败。
或者,您可以使用!在第一个递归子句中,将条件放在第二个:
countOdds([X|Xs],Y1) :- odd(X), !, countOdds(Xs,Y), Y1 is Y+1.
countOdds([X|Xs],Y) :- countOdds(Xs,Y).
答案 1 :(得分:4)
在Prolog中,您可以使用递归来检查递归数据结构的元素,如列表所示。 模式匹配允许选择要应用的正确规则。 完成任务的琐碎方式:
你有一个list = [X | Xs],每个元素X,如果是奇数(X)则返回countOdds(Xs)+1 else返回countOdds(Xs)。
countOdds([], 0).
countOdds([X|Xs], C) :-
odd(X),
!, % this cut is required, as rightly evidenced by Alexander Serebrenik
countOdds(Xs, Cs),
C is Cs + 1.
countOdds([_|Xs], Cs) :-
countOdds(Xs, Cs).
注意if
使用不同的same
模式规则处理:当Prolog找到非奇数元素时,它会回溯到最后一条规则。
ISO Prolog有If Then Else
的语法糖,您可以写
countOdds([], 0).
countOdds([X|Xs], C) :-
countOdds(Xs, Cs),
( odd(X)
-> C is Cs + 1
; C is Cs
).
在第一个版本中,递归调用遵循测试odd(X)
,以避免无效访问list'tail应该在回溯时重复。
编辑如果没有剪切,我们会得到多个执行路径,因此在“所有解决方案”谓词(findall,setof等等)下可能出现错误结果
最后一个版本证明该程序不是tail recursive
。要获得尾递归过程,请添加accumulator
:
countOdds(L, C) :- countOdds(L, 0, C).
countOdds([], A, A).
countOdds([X|Xs], A, Cs) :-
( odd(X)
-> A1 is A + 1
; A1 is A
),
countOdds(Xs, A1, Cs).