Prolog - 统一两个列表 with/without 变量

Prolog - unifying two lists with/without variables

此 Prolog 代码 returns:

?- [a,b,c,d]  =  [a|[b,c,d]].

正确

还有这个

?- [X,Y] = [a|[b,c,d]].

returns 错误。

我不太明白为什么 [X, Y] 是错误的。跟踪在这里没有帮助。我希望以下作业能够保持

X = a
Y = [b,c,d]

且该陈述为真。

|除了头尾分开还有什么作用?

Prolog 中的列表是作为仿函数的链表实现的。如果你写一个像 [a, b, c, d] 这样的列表。它在现实中看起来像:

+-------+
| (|)/2 |
+---+---+   +-------+
| o | o---->| (|)/2 |
+-|-+---+   +---+---+   +-------+
  v         | o | o---->| (|)/2 |
  a         +-|-+---+   +---+---+   +-------+
              v         | o | o---->| (|)/2 |
              b         +-|-+---+   +---+---+   
                          v         | o | o----> []
                          c         +-|-+---+
                                      v
                                      d

或 Prolog 符号 [a | [b | c | [d | [] ] ] ]。逗号分隔的列表是 语法糖 :如果你写 [a, b, c, d],Prolog 解释器将它转换为上面的表示。

因为 [b, c, d] 等于:

[ b | [ c | [ d | [] ] ] ]

因此 [ a | [b, c, d] ] 等于

[a | [b | c | [d | [] ] ] ]

但是列表[X, Y]正好等于

[X, Y] == [ X | [ Y | [] ] ]

或以结构方式:

+-------+
| (|)/2 |
+---+---+   +-------+
| o | o---->| (|)/2 |
+-|-+---+   +---+---+
  v         | o | o----> []
  X         +-|-+---+
              v
              Y

如果我们再将其与 [a | [b | c | [d | [] ] ] ] 匹配,这意味着可以匹配 "outer" shell,因此 X = a,但随后 Y = b,并且 [] = [ c | [ d | [] ] ]。最后一部分不匹配,因此它 returns falseXY 因此不是问题。问题是 [] 是一个常量,它与表示 [ c | [d] ].

的函子不匹配

如果我们统一 [ X | Y ] == [a, b, c, d] 我们得到:

?- [ X | Y ] = [a, b, c, d].
X = a,
Y = [b, c, d].

所以总而言之,可以说 | 本身 "does" 什么都没有。它是一个仿函数,就像 f(1, 2) 一样。在 Lisp 中,他们为此使用 cons [wiki],而 nil 用于空列表。所以 [1, 4, 2, 5] 在 Lisp 中看起来像 cons 1 (cons 4 (cons 2 (cons 5 nil))),或者在 Prolog 中看起来像 cons(1, cons(4, cons(2, cons(5, nil))))。只是写起来有点麻烦。事实上,逗号分隔符号更多的是 "magic" 部分。 Prolog 只是对列表进行合一,就像它对其他函子和常量所做的那样。