Haskell 广度与模式匹配

Haskell 广度与模式匹配,haskell,pattern-matching,Haskell,Pattern Matching,span函数定义如下。我很好奇(ys,zs)模式如何与(x:ys,zs)匹配,其中已经有一个“x”和一个cons。我有点相信模式匹配是一种就地替代,但这让我大吃一惊。这真是太美了 我很好奇,是否有任何一本书解释了这个结构以及更多的内容(我目前正在阅读真实世界的哈斯克尔第4章,不知道这本书或其他任何一本书是否详细解释了这一点)。很抱歉,如果我说我很天真,但对我来说,这是一个很好的模式匹配构造,我想知道更多 span p [] = ([],[]) span p xs@(x:xs

span函数定义如下。我很好奇(ys,zs)模式如何与(x:ys,zs)匹配,其中已经有一个“x”和一个cons。我有点相信模式匹配是一种就地替代,但这让我大吃一惊。这真是太美了

我很好奇,是否有任何一本书解释了这个结构以及更多的内容(我目前正在阅读真实世界的哈斯克尔第4章,不知道这本书或其他任何一本书是否详细解释了这一点)。很抱歉,如果我说我很天真,但对我来说,这是一个很好的模式匹配构造,我想知道更多

span p []            = ([],[])
span p xs@(x:xs') 
            | p x       =  (x:ys,zs)
            | otherwise =  ([],xs)
                           where (ys,zs) = span p xs'

许多模式语法也可用于表达式,因此,您可以使用与使用表达式构建数据相同的语法来使用模式分解数据

请注意,由于Haskell值是不可变的,因此没有就地替换。 部分
(x:ys,zs)
本身并不是一个模式,而是一个表达式,它根据本身来自模式的
x
ys
zs
值构建一个新值

x
来自模式
xs@(x:xs')
,并绑定到作为
span
的第二个参数传递的列表的第一个元素。这还将
xs'
绑定到列表的其余部分,并将
xs
绑定到原始整体。(
@
的意思是“将模式匹配到右侧,但同时给出绑定到整体的名称,这是模式也可以用作表达式的规则的一个例外。)

ys
zs
来自
中的模式
(ys,zs)
,其中(ys,zs)=span p xs'
。它们被绑定到从
span p xs'
的递归调用返回的元组的第一个和第二个元素,在
x
被删除后,列表的其余部分被删除

把这些放在一起,表达式
(x:ys,zs)
生成一个元组,该元组与从递归
span p xs'
返回的元组相同,只是
x
已使用到第一个元组元素

其他人必须回答关于书籍的问题,我很久以前就学会了Haskell,所以没有读过这些书。但是,如果其他方面都失败了,你可以读这些书。

你是对的,这很漂亮。这是最接近Prolog的书,在Haskell

让我解释一下,这个定义相当于

span p xs = case xs of 
             (x:t) | p x -> let (ys,zs) = span p t in
                            (x:ys,zs)   -- value1
             _           -> ([],xs)     -- value2 constructed from known parts
因为Haskell是惰性的,
value1
被构造并立即返回,而不需要任何中间递归调用,就像简单的
value2
一样。此时,
x
已经被知道(它被绑定为模式匹配的一部分)但是,
ys
zs
尚未计算-只是它们的定义保留在
值1
旁边,其中有两个“孔”
(x:,)
。仅当其中一个“孔”“稍后将需要值,通过进一步调用
span
并用分解结果填充这些漏洞来计算它们的值(
let
绑定也是模式匹配)

这在Haskell中称为保护递归-递归调用由构造函数保护-在这里,
(,)
(:)
-创建值,然后根据需要填充

顺便说一句,在序言中,这写为

span(P,[], [],[]).       % -- two "inputs", two "outputs"
span(P,XS, A,B):- 
  XS = [X|T],
  ( call(P,X) ->         % -- predicate P holds for X:
      A=[X|YS], B=ZS,    % --   first, the value with holes is created
      span(P,T, YS,ZS)   % --   then, the holes are filled
    ;                    % -- else:
      A=[], B=XS ).      % --   output values are set