foldTree 分步评估

foldTree step-by-step evaluation

提问人:F. Zer 提问时间:9/9/2021 最后编辑:Will NessF. Zer 更新时间:9/10/2021 访问量:80

问:

假设 、 和 a 函数的这些定义:foldTreeTreef

foldTree : (a -> [b] -> b) -> Tree a -> b
foldTree f = go
    where
        go (Node x ts) = f x (map go ts)

tree :: Tree String
tree = Node
      "Alpha"
      [ Node "Beta" [Node "Epsilon" [], Node "Zeta" [], Node "Eta" []]
      , Node "Gamma" [Node "Theta" []]
      , Node "Delta" [Node "Iota" [], Node "Kappa" [], Node "Lambda" []]
      ]

f x xs = [x] <> (map ('\t' :) (concat xs))

我将尝试评估:foldTree f tree

  foldTree f tree
= go (Node "Alpha" [ Node "Beta" [Node "Epsilon" [], Node "Zeta" [], Node "Eta" []], Node "Gamma" [Node "Theta" []], Node "Delta" [Node "Iota" [], Node "Kappa" [], Node "Lambda" []]]
= f "Alpha" (map go [...])
...

在这一点上,我的问题是:方程推理如何与闭包一起工作?has 的定义 ;但是,这肯定不是在其参数之间。有没有什么技巧可以插入该定义?gof

Haskell 函数编程 示波器 闭包 评估

评论


答:

2赞 Will Ness 9/9/2021 #1

简单地说,一个定义可以指代范围内的任何名称。

“闭合”是一个在存在突变的情况下更相关的概念。在Haskell中,没有“范围”的概念就足够了。

go的定义嵌套在 的 中,因此可以访问其参数。换句话说,在 的定义中,在范围内。foldTreefgof

定义可以改写为

{-
foldTree f t = go t
    where
         go (Node x ts) = f x (map go ts)
-}
foldTree f t =
   let { go (Node x ts) = f x (map go ts) } 
   in go t

任何调用的计算结果为foldTree f1 t1

> foldTree f1 t1 
=>
  let { f=f1; t=t1 }
  in
    let { go (Node x ts) = f x (map go ts) } 
    in go t
=>
  ....

这些是简单的嵌套 S,因此内部的 S 可以访问外部定义的每个名称。let

为了更容易地了解发生了什么,请尝试首先使用更简单的示例数据(如 、 等)对其进行评估。Node "Alpha" []Node "Alpha" [Node "Beta" []]


例如,使用

f0 x xs = [x] <> (map ('\t' :) (concat xs))

对收益的评估为Node "Alpha" []

> foldTree f0 (Node "Alpha" []) 
=>
  let { f=f0; t=Node "Alpha" [] }
  in
    let { go (Node x ts) = f x (map go ts) } 
    in go t
=>
  let { f x xs = [x] <> (map ('\t' :) (concat xs))
      ; go (Node x ts) = f x (map go ts) 
      } 
  in go (Node "Alpha" [])
=>
  let { f x xs = [x] <> (map ('\t' :) (concat xs))
      ; go (Node x ts) = f x (map go ts) 
      ; (Node x1 ts1) = (Node "Alpha" [])
      } 
  in f x1 (map go ts1)
=>
  let { f x xs = [x] <> (map ('\t' :) (concat xs))
      ; go (Node x ts) = f x (map go ts) 
      ; x1 = "Alpha"
      ; ts1 = []
      ; xs1 = map go ts1
      } 
  in [x1] <> (map ('\t' :) (concat xs1))
=>
  ["Alpha"] <> (map ('\t' :) (concat []))
=>
  ["Alpha"] <> (map ('\t' :) [])
=>
  ["Alpha"] <> []
=>
  ["Alpha"]

评论

0赞 F. Zer 9/9/2021
非常感谢你,@Will尼斯!!一个问题:在第一个代码块中,你有一个子句和一个表达式,我无法编译它。有没有可能修复它?wherelet
0赞 F. Zer 9/9/2021
伟大。现在它运行良好。关于第二块代码,您能告诉我如何使用替换定义吗?那里有很多关键字。有什么诀窍可以理解它吗?letin
1赞 Will Ness 9/9/2021
每个都只有一个,紧随其后的那个。想象一下括在括号中的内部:。虽然这些 paren 当然不是必需的,但无论如何代码都是这样解析的。letinlet...in...let { f=f1; t=t1 } in ( let { go (Node x ts) = f x (map go ts) } in ( go t ) )
0赞 F. Zer 9/9/2021
我明白了内在的来源。但是,我看不出最外层是从哪里来的。您的定义不包括它。你能解释一下吗?letletfoldTree
0赞 F. Zer 9/9/2021
我想我开始明白了!再次感谢您的帮助。你能告诉我这个评价是否正确吗?