模式匹配 - Prolog与Haskell

时间:2012-03-20 02:53:44

标签: haskell prolog pattern-matching

这不是一个家庭作业问题,而是一个考试学习指导问题。 Prolog Vs Haskell中的模式匹配有什么区别?

我做了一些研究,阅读背后的理论并没有真正让我对两者有充分的理解。我在Prolog中读到,模式匹配是不同的,因为它具有统一变量的能力,因此能够通过分辨率推断并吐出可能的答案

eg ?- [a,b] = [a,X]
   X = b

现在我不确定如何在Haskell中显示模式匹配。我知道Prolog中显示的上述相同查询在Haskell中不起作用,因为Haskell无法像Prolog那样统一。我记得在Haskell得到相同答案的地方,你必须通过警卫明确告诉它。

我知道我非常接近理解它,但是我需要有人为我分解Barney风格所以我可以完全理解它并向12岁的人解释它。这已经困扰了我很长一段时间,我似乎无法找到一个可靠的解释。

顺便说一句,上面的例子只是向你们展示我到目前为止所学到的东西,而我实际上是想找到答案。我的主要问题与上述例子无关,而是对两者之间差异的完整理解。

5 个答案:

答案 0 :(得分:44)

Prolog模式匹配基于统一,特别是Martelli-Montanari Algorithm(默认情况下减去发生的检查)。该算法匹配相同位置的值,一侧的绑定变量与另一侧的相应位置的值。这种模式匹配可以双向工作,因此在Prolog中你可以使用参数作为输入和输出。一个简单的例子,length/2谓词。我们可以使用它(注释解释查询):

?- length([],0).      % is the length of empty list zero?
?- length([a,b,c],X). % what's the length of list consisting of a,b and c?
?- length(L,5).       % give me all lists that have length of 5

Haskell pattern matching是单向匹配,用于将变量绑定到给定值的不同部分。一旦绑定,它就会执行相应的操作(右侧)。例如,在函数调用中,模式匹配可以决定调用哪个函数。 e.g:

sum []     = 0
sum (x:xs) = x + sum xs

第一个总和绑定空列表,而第二个绑定至少一个元素的列表。基于此,给定sum <a list>,结果可以是0x + sum xs,具体取决于sum <a list>是否与sum []sum (x:xs)匹配。

答案 1 :(得分:13)

Haskell和Prolog统一中的模式匹配之间的区别源于两种语言中变量的根本不同。

在Haskell中,变量包含值。具体价值观。这样的值可能尚未计算,甚至可能是⊥,但除此之外它是一个具体的值。在Haskell中,您不能接受变量,只能首先声明其值的某些属性。

因此模式匹配总是意味着具体值与包含一些变量的模式匹配。这种匹配的结果是失败或将变量绑定到具体值。在Haskell中,这进一步限制为避免需要进行一般比较,这意味着为匹配的术语定义了类Eq

然而,在Prolog中,变量可能指的是一组可能的解决方案。变量可能出现在任何地方 - 也介于其他值之间。统一现在确保所述等式仍然成立并且结果以最佳方式表示,即计算最通用的统一者。


| ?- length(L,5).                      
L = [_,_,_,_,_]
| ?- length(L,5), maplist(=(E),L).
L = [E,E,E,E,E]

所以Prolog不会在这里回答L = [1,1,1,1,1]L = [[],[],[],[],[]]这样的具体值,而是给出最常用的统一者作为包含所有具体值的答案。

答案 2 :(得分:7)

没有人提到以下非常重要的区别。 Prolog中的模式匹配尝试用于谓词的每个子句,即使之前的一个匹配成功(除非通过 cut 停止)。但是在Haskell中,只有才会尝试匹配子句,直到第一次成功。没有尝试其他替代方案(除非比赛被后卫拒绝)。

Prolog的模式匹配在最普遍意义上建立了一个等式约束(详见@false的回答)。 分享是明确的A=B, A=5也设置了B=5。这是可能的,因为Prolog的logvar可能尚未设置(即未实例化)状态。这使得 tying-a-knot 变得容易(实际上是一种基本的编程技术,即差异列表)。

在Haskell中,允许在语法级别仅一次定义任何变量。在Prolog中,logvar 设置只能一次<无法回复,但是它允许指向不完整的结构(数据),其中孔由其他尚未实例化的logvar表示,可以在以后的任何时间点设置。

在Haskell中,根据访问要求逐步充实了一个用保护递归定义的给定结构。在Prolog中,在变量的初始实例化之后,任何后续的统一都将变为对术语兼容性的验证以及可能的进一步(可能是部分再次)实例化(“填充” “漏洞明确地)。

答案 3 :(得分:5)

添加到LeleDumbo的答案,我们可以说Prolog统一构建术语以及解构它们,而在Haskell中,构建阶段很方便地要求返回值

当然,这样的特性允许纯Prolog所谓的“双向”谓词,例如在DCG中被利用,有一些限制,可以用于解析和生成。

答案 4 :(得分:5)

这是一个我在Prolog中感兴趣的例子,支持@chac(+1 btw)提及Prolog的统一“构建”我们昨天在prolog标签中遇到的术语:

swapPairs([],       []).
swapPairs([X],      [X]).
swapPairs([X, Y|T], [Y, X|R]) :- swapPairs(T, R).

这个谓词几乎没有“身体”。它只在头部和递归中使用其参数的统一。

正如@chac和@LeleDumbo所指出的,那是因为Prolog的统一是“双向的”。

这是一个温和的Haskell简介所说的:

  

Haskell中的模式匹配与逻辑中的模式匹配不同   编程语言,如Prolog;特别是,它可以被看到   作为“单向”匹配,而Prolog允许“双向”匹配(通过   统一),以及评估中的隐含回溯   机构。