【问题标题】:What's wrong with my Prolog "list filler"?我的 Prolog“列表填充”有什么问题?
【发布时间】:2017-09-20 07:02:40
【问题描述】:

我编写了一个简单的程序来尝试使用满足特定约束的元素填充给定长度的列表。

例如,我想创建一个包含 0 到 9 之间的 4 个整数的列表,其中至少包含 34。我能想到几个(实际上是数千个)这样的列表:

[3,4,0,0]
[0,3,4,0]
[3,1,9,4]
etc...

但 SWI Prolog 只返回 false。我只是犯了某种逻辑错误,还是我使用 Prolog 错误?

我的代码:

is_single_digit_integer(N) :-
  integer(N),
  between(0, 9, N).

filled_list(Given, FillConstraint, OutLen, Out) :-
  is_list(Out),
  length(Out, OutLen),
  length(Given, GivenLen),
  between(0, OutLen, GivenLen),
  maplist(FillConstraint, Out),
  subset(Given, Out).

并运行我描述的示例:

?- filled_list([3,4], is_single_digit_integer, 4, X).

【问题讨论】:

    标签: prolog


    【解决方案1】:

    我想用指向 的简短指针来补充丹尼尔的回答:

    通用 Prolog 程序的 via regia 是使用满足您对逻辑关系所期望的属性的谓词。这样的谓词称为puremonotonic

    例如,在您的特定情况下,您正在使用 非单调 谓词 integer/1is_list/1。如果您改为使用可在所有方向使用的谓词,您的问题就会完全消失,例如:

    is_single_digit_integer(N) :- N 在 0..9.

    这使用 约束(in)/2 来声明:N 是一个介于 0 和 9 之间的整数

    它适用于以下所有情况:

    ?- is_single_digit_integer(N)。 N 在 0..9. ?- is_single_digit_integer(3)。 是的。 ?- is_single_digit_integer(20)。 错误。

    相比之下,integer/1不完整的

    ?- 整数(N)。 错误。

    →不存在整数??

    is_list/1 也是如此,对于最一般的查询来说已经严重不足:

    ?- is_list(Ls)。 错误。

    相比之下,要声明Ls 是一个列表,您可以例如使用:

    长度(Ls,_)

    这可以正常工作无论是否 Ls 被实例化。例如:

    ?- 长度(Ls,_)。 LS = [] ; LS = [_6650] ; Ls = [_6650, _6656] ; Ls = [_6650, _6656, _6662] ; 等等

    为了充分利用 Prolog,我建议保留在其纯粹且单调的子集中。这为可以在各个方向使用的关系铺平了道路。

    【讨论】:

      【解决方案2】:

      integer(N)is_list(Out) 都假定绑定变量并在未实例化的变量上失败。解决方案是删除它们:

      is_single_digit_integer(N) :-
        between(0, 9, N).
      
      filled_list(Given, FillConstraint, OutLen, Out) :-
        length(Out, OutLen),
        length(Given, GivenLen),
        between(0, OutLen, GivenLen),
        maplist(FillConstraint, Out),
        subset(Given, Out).
      

      您现在可以看到它可以工作了:

      ?- filled_list([3,4], is_single_digit_integer, 4, X).
      X = [0, 0, 3, 4] ;
      X = [0, 0, 4, 3] ;
      X = [0, 1, 3, 4] ;
      X = [0, 1, 4, 3] .
      

      我认为您正在尝试将这些谓词用作类型约束,但 Prolog 不能那样工作。相信你的类型,一切都会好起来的;毕竟,between 只会给你整数,length 只会给你列表。

      奖励技巧:

      ?- filled_list([3,4], between(0,9), 4, X).
      X = [0, 0, 3, 4] ;
      X = [0, 0, 4, 3] ;
      X = [0, 1, 3, 4] ;
      X = [0, 1, 4, 3] ;
      X = [0, 2, 3, 4] .
      

      【讨论】:

      • 很高兴了解lengthbetween。我确实试图施加类型限制。如何判断谓词是否假定其输入是绑定的?只是文档中的“+ParamName”,还是更基本的东西?
      • @ssdecontrol 不幸的是,文档是唯一真正的方法。 (如果您的优先级列表中没有 REPL,您可能会喜欢在 Mercury 中编程,它结合了类似 Haskell 的类型系统和比 Prolog 更强大的声明式编程模型,但保留了 Prolog 的大部分语法)。
      • @ssdecontrol:我认为这值得单独提出一个问题!
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-06-01
      • 1970-01-01
      • 2017-01-21
      • 1970-01-01
      • 2013-09-18
      • 2014-08-01
      相关资源
      最近更新 更多