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 false
。 X
和 Y
因此不是问题。问题是 []
是一个常量,它与表示 [ 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 只是对列表进行合一,就像它对其他函子和常量所做的那样。
此 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 false
。 X
和 Y
因此不是问题。问题是 []
是一个常量,它与表示 [ 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 只是对列表进行合一,就像它对其他函子和常量所做的那样。