2012-04-19 70 views
1

我开始为即将到来的考试而学习,而我被困在一个不重要的prolog练习题上,这不是一个好兆头。为prolog/haskell编程考试而努力

它应该很容易,但由于某种原因,我现在无法弄清楚它。

这个任务是简单地计算序列中Int列表中的奇数个数。 我在哈斯克尔很容易做到了,但是我的序言很糟糕。有人能告诉我一个简单的方法来做到这一点,并简要解释你做了什么?

到目前为止,我有:

odd(X):- 1 is X mod 2. 

countOdds([],0). 
countOdds(X|Xs],Y):- 
????? 

回答

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模式不同的规则处理:在序言找到一个非奇的元素,它退回到最后一个规则。

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). 
+0

感谢,真的帮了我对这个问题以及其他问题,我不得不:) – user1204349 2012-04-19 07:33:46

5

你的奇/ 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).