【问题标题】:Prolog - Arguments are not sufficiently instantiatedProlog - 参数没有充分实例化
【发布时间】:2023-03-20 21:45:01
【问题描述】:

我正在编写一个小程序来计算列表中有多少元素不是数字。 这是我的代码:

not_number([],0).
not_number([X|T],R):- 
    not(number(X)),
    R1 is R+1,  
    not_number(T,R1). 

not_number([_|Tail],Result):-
    not_number(Tail,Result).  

如果我执行这样的代码:

?- not_number([1,2,3,5], R).

我得到 R = 0(应该是这样)

R = 0.

但是如果我把一个字符放在列表中:

?- not_number([1,2,3,5,a], R).

然后我收到此错误:

ERROR: not_number/2: Arguments are not sufficiently instantiated
   Exception: (10) not_number([a], _G247) ? 

有人能解释一下代码有什么问题吗?我是 prolog 的新手。

【问题讨论】:

  • 因为在not_number([a], R) 的情况下没有实例化R 时,您正在执行R1 is R+1。您的递归案例有点倒退。你想做not_number(T, R1), R is R1+1
  • This pageis也有很好的讨论

标签: prolog arguments instantiation-error


【解决方案1】:

我正在写这个答案,因为迄今为止最好的答案是在lurkercomment 中。我想让它显示为一个实际的答案。

您的代码不起作用,因为在 not_number([X|T], R) 的情况下未实例化 R 时,您正在执行 R1 is R+1。您的递归案例有点倒退。你想这样做:

not_number([X|T],R):- 
    not(number(X)),
    not_number(T,R1),
    R is R1+1.

现在is的右侧在被调用时被实例化。

【讨论】:

    【解决方案2】:

    你的问题是在这样的算术计算中:

    A 是 B

    右侧 (B) 的所有内容都必须是已知的。那里没有变量。

    你可以这样做:

    not_number(X, Y) :- not_number(X, Y, 0).
    not_number([], Y, Y).
    not_number([H|T], Y, Z) :-
        \+ (number(H)), 
        Z1 is Z+1,
        not_number(T, Y, Z1).
    
    not_number([H|T], Y, Z) :-
        number(H),
        not_number(T, Y, Z).
    

    (现在测试了这段代码,它可以工作)。

    现在第三个参数是一个累加器。它计算有多少个非数字。当列表为空时,第三个参数与第二个参数统一,成为正确答案。

    如果有机会,Prolog 将走遍所有可能的路线。如果你这样做:

    cat(adam).
    cat(eve).
    

    然后问:

    ?- cat(X).
    

    你可以得到两个答案:X = 亚当和 X = 夏娃。 它也适用于您的代码:请注意,当列表的头部不是数字时,您仍然可以这样做:

    not_number([_|Tail],Result):-
        not_number(Tail,Result).  
    

    它没有给出你想要的答案。你必须切断你不感兴趣的路线。在这种情况下,我会添加

    number(Head).
    

    确保我们跳过列表中的一个元素,而不会将计数器加 1,仅当该元素不是数字时。

    要强制 Prolog 查找其他结果,您必须按“;”在你的键盘上(就像这个亚当和夏娃的例子)。

    【讨论】:

      【解决方案3】:

      此类问题的一般解决方案是使用约束

      例如,如果您只使用 约束,您的程序将完全按预期运行。只需将(is)/2 替换为(#=)/2 即可获得在所有方向都有效的整数运算:

      :- use_module(library(clpfd)).
      
      not_number([],0).
      not_number([X|T],R):- 
          \+ number(X),
          R1 #= R+1,  
          not_number(T,R1). 
      
      not_number([_|Tail],Result):-
          not_number(Tail,Result).
      

      示例查询及其结果:

      ?- not_number([1,2,3,5], R)。 R = 0。

      另请注意,我已将代码更改为使用 ISO 谓词 (\+)/1 而不是 not/1

      【讨论】:

      • ?- not_number([A,A,B],N). 有一个解决方案,N = -3。这对我来说不合适。
      • 罪魁祸首? number/1,当然,因为它将实例化测试与类型测试混合在一起。解决方法:functor(X,_,_), \+ number(X) 而不是 \+ number(X)。或者,更好的是,if_/3 带有正确的具体化测试谓词......
      • 非常正确。我建议must_be(nonvar, X)。现在可以讨论这一点,因为 OP 报告的基本问题是通过使用声明性算术解决的。
      • 对,我没有注意到这两个代码的相似之处。
      【解决方案4】:

      在我的情况下,我必须使用 is 而不是 =

      不是这个

      X is AnotherVariable
      

      我不得不写

      X = AnotherVariable
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-07-26
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2023-04-02
        • 1970-01-01
        相关资源
        最近更新 更多