攻读prolog / haskell编程考试

时间:2012-04-19 05:24:54

标签: syntax prolog

我开始为即将到来的考试学习,但我仍然坚持一个琐碎的prolog练习题,这不是一个好兆头lol。

这应该很容易,但由于某些原因我现在无法弄明白。

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

到目前为止,我有:

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

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

2 个答案:

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