26

我以为我了解在 Scala 和 Haskell 中发现的模式匹配与在 Prolog 中发现的统一性有何不同,但我对 Prolog 的误解很大。有哪些简单的问题可以由一个人解决而另一个人无法解决?谢谢

4

4 回答 4

32

简单的说法:模式匹配是单向的,统一是双向的。也就是说,在 Prolog 中,右侧(被匹配的那个)可以包含未绑定的变量。例如,如果您有两个未绑定的变量XY,这将正常工作:

X = Y,
X = 5,
%% Y = 5 now as well

在 Erlang(使用接近 Prolog 语法的模式匹配)中,该行将X = Y产生错误:variable 'Y' is unbound. 请注意,X未绑定很好:它应该是模式匹配的。

当您想要处理部分定义的值时,这可能很有用。一个很好的例子是差异列表

这也是允许在多种模式下使用 Prolog 谓词的原因。例如,在 Scala/Haskell/Erlang 中,如果你想 1) find A ++ B,2) 求解方程A ++ X == B,或 3) 求解X ++ A == B给定列表的方程AB,你需要编写 3 个单独的函数;在 Prolog 中,所有这些工作(以及更多!)都由一个谓词完成。

于 2010-12-14T17:52:39.980 回答
8

我认为将概念形式化而不是研究特定的语言是有用的。匹配和统一是比模式匹配和序言在更多上下文中使用的基本概念。

  • 项 s 匹配 t,当且仅当存在替换 phi 使得 phi(s) = t
  • 项 s 与项 t 合一,当且仅当存在 phi(s) = phi(t)

举个例子,我们检查术语 s = f(Y,a) 和 t = f(a,X) 其中 X,Y 是变量,a 是常数。s 不匹配 t,因为我们不能普遍量化常数 a。但是,s 和 t 有一个统一符:phi = {X\a, Y\a}

于 2016-03-15T15:00:59.217 回答
1

Scala 中的以下内容将无法编译,因为它的第一种情况分支尝试x两次声明变量。

(1, 1) match{
   case (x, x) => println("equals")
   case _      => println("not equals")
}

如果 Scala 使用统一而不是模式匹配,这将成功并打印“等于”,而

(1, 2) match{
   case (x, x) => println("equals")
   case _      => println("not equals")
}

将打印“不等于”。这是因为当尝试将变量绑定x1和时,统一会失败2

于 2010-12-14T18:10:07.370 回答
1

在 Prolog 中,您可以像这样将 [3] 附加到 [1,2] :

?- append([1,2], [3], Z).
Z = [1, 2, 3].

统一的巧妙之处在于您可以使用相同的代码('append' 的内部定义),而是找到从第一个参数获取结果所需的第二个参数:

?- append([1,2], Y, [1,2,3]).
Y = [3].

不是通过编写“做这个,然后做那个”来编码,而是通过说出你所知道的来在 Prolog 中编码。Prolog 将您提供的事实视为方程式。统一让它采用这些方程并求解您还不知道其值的任何变量,无论它们是在右侧还是左侧。

因此,例如,您可以在 Prolog 中编写一个计划器,然后您可以“向前”运行它,给它一个计划并让它预测其结果;或者你可以“向后”运行它,给它一组结果并让它构建一个计划。你甚至可以同时以两种方式运行它(如果你在编码时小心的话),指定一组目标和一组对计划的约束,这样你就可以说“找到一个不涉及工作的计划坐地铁。”

于 2014-06-12T21:41:25.697 回答