这是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]
有人可以分解那个例子吗?
答案 0 :(得分:2)
我不理解的部分是应该提供内功能的
(#. f)
x -> x
请记住,Haskell函数是curry。所以f :: a -> b -> b
是一个单参数函数,它接受a
并返回一个内同态b -> b
。 Endo #. f
将f
(函数b -> b
)的结果检测到Endo
,该函数需要函数作为参数。
以下是其详细工作原理:
首先,请注意(#.)
基本上是(.)
的同义词。你有
foldr f z t = appEndo (foldMap (Endo . f) t) z
在Skolemnising a
和b
之后(f :: A -> B -> B
对于刚性类型A
和B
),表达式(. 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]