【问题标题】:Span and pattern matching跨度和模式匹配
【发布时间】:2014-08-24 14:02:18
【问题描述】:

span 函数定义如下。我很好奇 (ys, zs) 是如何与 (x:ys, zs) 模式匹配的,其中已经有一个'x'和一个缺点。我如何相信模式匹配将是一个就地替代,但这让我大吃一惊,让我的下巴掉了下来。这真的很漂亮。

我很好奇是否有任何一本书解释了这个结构以及更多内容(我目前正在阅读 Real World Haskell 第 4 章,想知道这本书或任何其他书是否详细解释了这一点)。对不起,如果我表现得天真,但对我来说,这是一个很好的模式匹配结构,我很想知道更多。

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

【问题讨论】:

    标签: haskell pattern-matching


    【解决方案1】:

    你是对的,这美丽的。它是最接近 Prolog 在 Haskell 中的 TRMC 的东西。

    让我解释一下。该定义等价于

    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 是已知的(它被绑定为模式匹配的一部分)但yszs 尚未计算——只是它们的定义与value1 一起保留,其中有两个“孔”, (x:_,_)。仅当稍后需要任何“空洞”值时,才会通过进一步调用 span 并用解构结果填充这些空洞来计算它们的值(let 绑定也是模式匹配)。

    这在 Haskell 中称为受保护递归 - 构造函数会保护递归调用 - 这里是 (,)(:) - 使用孔创建值,稍后根据需要填充。

    顺便说一下,在 Prolog 中这写成

    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
    

    【讨论】:

      【解决方案2】:

      许多模式语法也可用于表达式,因此您可以使用 same 语法将数据与模式分开,就像使用表达式构建数据一样。

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

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

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

      将这些放在一起,表达式(x:ys,zs) 构成一个元组,它与从递归span p xs' 返回的元组相同,只是x 已被转换为第一个元组元素。

      其他人将不得不回答有关书籍的问题,我很早就学会了 Haskell,无法阅读它们。但如果一切都失败了,你可以阅读precise definitions in the Haskell report

      【讨论】:

        猜你喜欢
        • 2021-12-24
        • 1970-01-01
        • 2022-01-11
        • 2012-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2013-08-19
        • 2019-05-01
        相关资源
        最近更新 更多