繁体   English   中英

索引折叠器如何在操作上工作?

[英]How does indexed foldr work operationally?

我无法理解定义:

ifoldr :: Foldable f => (Int -> a -> b -> b) -> b -> f a -> b
ifoldr f z xs = foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0

特别是,似乎通过避免zip [1..]来避免空间泄漏,同时它似乎派生出一个新的折叠“阶梯函数”,前面给出了额外的参数,但这个参数最后在\\ xgi传递!

对于某些具有保留非严格性属性的定义f' = _unknown_ f ,这相当于f' = _unknown_ f f' x (foldr f' z xs) f' = _unknown_ f f' x (foldr f' z xs)吗?

简而言之foldr生成一个函数 (不是值列表),然后该函数将生成该列表。

让我们首先忽略foldr ,并专注于foldr中使用的函数,让我们调用这个函数eval

eval x g i = seq i (f i x (g (i+1))))

我们将忽略这里的seq :是的,它有一些语义:评估( 弱头正常形式i并检查i是否是底部,但让我们假设这不会引入底部。 所以eval - 或多或少 - 相当于:

eval x g i = f i x (g (i+1))

现在我们可以重新考虑foldr上下文:

ifoldr f = foldr eval (const z) xs 0
    where eval x g i = f i x (g (i+1))

现在定义了foldr (对于列表,但让我们在这里保持简单),如:

foldr _ z [] = z
foldr f z (x:xs) = f x (foldr f z xs)

对于包含三个元素[x1, x2, x3] ,这意味着:

foldr eval (const z) [x1, x2, x3]

好像:

-- foldr eval (const z) [x1, x2, x3] is equivalent to
eval x1 (eval x2 (eval x3 (const z)))

由于eval定义如上,这意味着我们可以将其专门化为:

\i1 -> f i1 x1 ((\i2 -> f i2 x2 (\i3 -> f i3 x3 (const z)) (i2 + 1)) (i1 + 1))

或者以某种方式使结构更清晰:

\i1 -> (
    f i1 x1
    \i2 -> (
        f i2 x2
        \i3 -> (
            f i3 x3
            (const z) (i3+1)
        ) (i2+1)
    ) (i1+1)
)

因此,您可以看到外部函数接受一个参数(此处为i1 ),并使用i1 (索引), x1 (第一项)调用f ,并作为最后一项调用“折叠”调用的结果“剩下的清单。 因此,我们使用i2作为参数进行调用,但是i2i1+1绑定。

因此,如果我们执行替换(用i2 + 1替换i3 ),这是lambda演算的工作方式,我们得到:

\i1 -> (
    f i1 x1
    \i2 -> (
        f i2 x2
        (
            f (i2+1) x3
            (const z) (i2+1+1)
        )
    ) (i1+1)
)

而且我们可以用i1+1代替i2

\i1 -> (
    f i1 x1
    (
        f (i1+1) x2
        (
            f (i2+1) x3
            (const z) (i1+1+1+1)
        )
)

由于(const z)映射到z ,参数是无论使用什么,我们可以替代(const z) (i1+1+1+1)z ,所以:

\i1 -> (
    f i1 x1
    (
        f (i1+1) x2
        (
            f (i1+1+1) x3
            z
        )
)

所以现在我们知道foldr eval (const z) [x1, x2, x3]映射到了什么,但是有一个最终的函数应用程序:最后的0

这意味着我们用0调用上面定义的lambda-expression,所以这会折叠为:

\i1 -> (
    f i1 x1
    (
        f (i1+1) x2
        (
            f (i1+1+1) x3
            z
        )
) 0

因此:

(
    f 0 x1
    (
        f (0+1) x2
        (
            f (0+1+1) x3
            z
        )
)

或以紧凑的形式:

(f 0 x1 (f 1 x2 (f 2 x3 z)))

所以我们设法在我们的解决方案中注入指数。

现在seq当然有一个功能:它会阻止为索引制作巨大的(左递归)表达式树,而不是((((1+1)+1)+1)+1)+1 ,它将确保每次我们递增它,它会立即被评估,因此我们永远不会获得1+1+1 ,但总是2+1 ,并且将它立即解析为3

如果(确实如此)

foldr c n (x:xs) = c x (foldr c n xs)  :: t

c x r = ...    -- r: mnemonic: recursive result

c x r :: t , r :: t , n :: t          -- same t

然后肯定 (通过eta扩展)

foldr c n (x:xs) i = c x (foldr c n xs) i  :: t

c x r i = ...   -- c = (\ x r i -> ... )

c x r i :: t , r i :: t , n i :: t        -- same t

所以我们可以拥有

ifoldr f n (x:xs) = foldr c n (x:xs) i = c x (foldr c n xs) i    :: t
                                       = f i x (foldr c n xs i')  :: t

c x r i = f i x (r i') 

c x r i :: t , r i :: t , n i :: t , f i x :: t -> t

而这正是你在那里所做的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM