Foldable中foldr实现的解释

时间:2018-06-17 20:46:12

标签: haskell

这是foldr的实现:

foldr :: (a -> b -> b) -> b -> t a -> b
foldr f z t = appEndo (foldMap (Endo #. f) t) z

我不理解的部分是(#. f)应提供内功能x -> x

例如foldr(:) [4,5] [1,2,3]

foldr (:) [4,5] [1,2,3] = appEndo (foldMap (Endo #. (:)) [1,2,3]) [4,5]
                        = appEndo (((Endo #. (:)) 1) <> 
                                   ((Endo #. (:)) 2) <> 
                                   ((Endo #. (:)) 3) ) [4,5]
                        = ???
                        = [1,2,3,4,5]

有人可以分解那个例子吗?

2 个答案:

答案 0 :(得分:2)

  

我不理解的部分是应该提供内功能的(#. f) x -> x

请记住,Haskell函数是curry。所以f :: a -> b -> b是一个单参数函数,它接受a并返回一个内同态b -> bEndo #. ff(函数b -> b)的结果检测到Endo,该函数需要函数作为参数。

以下是其详细工作原理:

首先,请注意(#.)基本上是(.)的同义词。你有

foldr f z t = appEndo (foldMap (Endo . f) t) z

Skolemnising ab之后(f :: A -> B -> B对于刚性类型AB),表达式(. f)有一种

(. f) :: forall r. ((B -> B) -> r) -> A -> r

Endo :: forall a. (a -> a) -> Endo a设为(.)的左参数,即可获得r ~ Endo B

Endo . f :: A -> Endo B

因为foldMap :: Monoid m => (a -> m) -> t a -> m

foldMap (Endo . f) :: Foldable t => t A -> Endo B

并且函数的其余部分自行编写。

这就是类型的运作方式。让我们打破你的榜样。

foldr (:) [1, 2, 3] [4, 5]
appEndo (foldMap (Endo . (:)) [1, 2, 3]) [4, 5]
appEndo (((Endo . (:)) 1) <> ((Endo . (:)) 2) <> ((Endo . (:)) 3) ) [4, 5]
appEndo (Endo (1:) <> Endo (2:) <> Endo (3:)) [4, 5]  -- beta reduce (.)
appEndo (Endo $ (1:) . (2:) . (3:)) [4, 5]  -- definition of (<>) for Endo
((1:) . (2:) . (3:)) [4, 5]  -- appEndo (Endo f) = f
[1, 2, 3, 4, 5]

答案 1 :(得分:1)

(. f),它是(Endo . f)

#. 就像 . (出于我们的目的),Endo就像任何其他功能一样。例如,

(Endo . (:)) 1 = Endo ((:) 1) = Endo (1:)    -- by definition of (.), (f . g) x = f (g x)

(1:)确实是一个内功能,其类型Num a => [a] -> [a]b -> b的更专业版,因此​​表达式Endo (1:)有意义(或者,#34;}类型&#34;或&#34;是一个很好的表达式&#34; - Endo 1,例如,不是)。

所以,如果你接受foldMap f [a,b,c] = f a <> f b <> f c

foldr (:) [4,5] [1,2,3] = appEndo (foldMap (Endo #. (:)) [1,2,3]) [4,5]
                        = appEndo (((Endo #. (:)) 1) <> 
                                   ((Endo #. (:)) 2) <> 
                                   ((Endo #. (:)) 3) ) [4,5]
                        = ??

然后,从这一点开始,它只是直接应用适当的定义/方程式:

   -- #. is like . 
                        = appEndo (((Endo  . (:)) 1) <> 
                                   ((Endo  . (:)) 2) <> 
                                   ((Endo  . (:)) 3) ) [4,5]
   -- (f . g) x = f (g x)
   -- (Endo . g) x = Endo (g x)
                        = appEndo (( Endo  ((:)  1)) <> 
                                   ( Endo  ((:)  2)) <> 
                                   ( Endo  ((:)  3)) ) [4,5]
                        = appEndo (( Endo  (1 :)   ) <> 
                                   ( Endo  (2 :)   ) <> 
                                   ( Endo  (3 :)   ) ) [4,5]
   -- (Endo f) <> (End g) = Endo (f . g)
                        = appEndo (( Endo  (1 :)   ) <> 
                                   ( Endo ((2 :) . (3 :)) )) [4,5]
                        = appEndo (  Endo ((1 :) . ((2 :) . (3 :))) ) [4,5]
   -- appendo (Endo f) = f
                        =                 ((1 :) . ((2 :) . (3 :)))   [4,5]
                        =                  (1 :) (  (2 :) ( (3 :)     [4,5] ))
                        =                  (1 :     (2 :    (3 :      [4,5] )))
                        =                   1 :      2 :     3 :      [4,5] 
                        = [1,2,3,4,5]