【问题标题】:Prolog - unifying two lists with/without variablesProlog - 统一两个有/没有变量的列表
【发布时间】:2018-10-29 13:59:09
【问题描述】:

此 Prolog 代码返回:

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

是的

还有这个

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

返回 false。

我没有完全理解为什么[X, Y] 是假的。跟踪在这里没有帮助。我希望以下任务能够举行

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

并且该陈述是正确的。

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

【问题讨论】:

  • [X,Y] 是 2 个元素的列表。 [a|[b,c,d]] 是一个包含 4 个元素的列表,相当于 [a,b,c,d]。所以这两个术语不能统一,因此是错误的结果。也许您打算写[X|Y] = [a|[b,c,d]], 是列表元素分隔符。 | 表示头尾关系。

标签: list variables prolog unification


【解决方案1】:

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 | [] ] ] ] 匹配,这意味着可以匹配“外部”外壳,因此X = a,然后是Y = b[] = [ c | [ d | [] ] ]。最后一部分不匹配,因此它返回falseXY 因此不是问题。问题是[]是一个常数,和代表[ c | [d] ]的函子不匹配。

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

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

总而言之,可以说| 本身“什么都不做”。它是一个仿函数,就像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))))。只是写起来有点麻烦。事实上,逗号分隔符号更像是“魔法”部分。 Prolog 只是对列表执行统一,就像它对其他仿函数和常量所做的一样。

【讨论】:

  • @user1700890: 没有[a, b] = f(a, f(b, nil))nil 是“空列表”(列表末尾)。请注意,Prolog 将[X|Y] 视为表示此类f(X, Y) 的“标准”方式。 [] 是语法的一部分。请注意f/2 有一个头和一个尾,因为[a,b] 然后a 是头,但b 不是 尾,b 是“下一个元素” ,因此我们需要一个列表作为尾部:[b],或者使用我们的仿函数f(b, nil)
  • 您可以将[X|Y] 视为编写f(X, Y) 的语法,但[X, Y] 是该概念的语法糖在顶部,从某种意义上说,这并不结果是 一个 函子,但在函子的结构中。
  • 再次感谢您。我想我现在很清楚了。让我们举个简短的例子:[X,Y] = [a|[b,c]],然后是[X,Y]=f(X, f(Y,nil))[a|[b,c]]= f(a,f(b,f(c,nil)))。所以这个说法是错误的,因为f(c, nil)nil不统一。
  • @user1700890: 确切地说:在 Prolog 中,一个常量只被认为与自身相等(通过统一,一个变量当然可以将该常量作为值),并且一个仿函数与相同的仿函数(相同的名称和相同的 arith) 并且所有的论点都是相同的。现在nilf(c, nil) 显然不相等,因为nil 是一个常数,而f 是一个有两个参数的函子。
  • @user1700890 nil 只是一个原子,就像joefoo 这样的术语。 nil 在 Prolog 中没有比任何其他原子更特殊的含义。就列表而言,在 Prolog 中列表 [H | T] 实际上是 '.'(H, T) 的语法糖,这是 Prolog 中列表的规范形式。 [X,Y] = f(X, f(Y,nil)) 失败是因为 f'.' 不是同一个函子。如果您使用'.' 而不是F,那么它仍然会失败,因为'.'(X, '.'(X,nil)) 可以写成[X, Y | nil]nil 原子不是空列表。空列表由特殊术语[] 表示。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-10-16
相关资源
最近更新 更多