Haskell中的scanl是如何在Either's列表上工作的-两种情况的比较

lrl1mhuk  于 2023-10-19  发布在  其他
关注(0)|答案(2)|浏览(108)

我正在尝试使用Haskell中的scanl函数。我已经缩小了我的问题,可以在以下两种情况下描述,这可以在解释器中使用包含scanl的Haskell中的普通库运行(注意,我不一定对Monadic值感兴趣,但只是如何使用scanl来确保类型一致性):
为什么下面的工作与预先列出的Right value s工作:

*Defs> scanl (\x acc -> x ++ acc) [] [[(Right 1)], [(Right 2)]]  
[[],[Right 1],[Right 1,Right 2]]

当这不起作用并导致以下错误消息时:

*Defs> scanl (\x acc -> [x] ++ acc) [] [(Right 1), (Right 2)]

<interactive>:36:35: error:
    * Couldn't match expected type `[[a]]'
                  with actual type `Either a0 b0'
   ...
v6ylcynt

v6ylcynt1#

我想你已经交换了值和累加器。考虑scanl的类型:

ghci> :t scanl
scanl :: (b -> a -> b) -> b -> [a] -> [b]

累加器值的类型为b。它是第一位的。
如果在第二个示例中交换参数,它可以工作:

ghci> scanl (\acc x -> acc ++ [x]) [] [(Right 1), (Right 2)]
[[],[Right 1],[Right 1,Right 2]]

你也可以交换第一个例子的参数,这也是可行的:

ghci> scanl (\acc x -> acc ++ x) [] [[(Right 1)], [(Right 2)]]
[[],[Right 1],[Right 1,Right 2]]
lnvxswe2

lnvxswe22#

你在这里要做的已经存在,这是**inits :: [a] -> [[a]]**,它产生所有前缀。您使用列表列表,但可以通过连接而不是假装来处理。
然而,每次构造一个新的列表,在右端追加,都需要*(n2),这是有意义的,因为总的构造确实是(n2)。但是,例如,我们可能只想生成最后一个列表。
因此,使用 difference list 可能会更好,它允许在 (1) 中添加一个元素,因此如果我们只想构造最后一个元素之一,最终只需要
(n2)* 时间。

dapp :: [a] -> ([a] -> [a]) -> [a] -> [a]
dapp [] f = f
dapp (x : xs) f = dapp xs (f . (x :))

dground :: ([a] -> [a]) -> [a]
dground = ($ [])

所以我们可以构造函数为:

ourInits :: [[a]] -> [[a]]
ourInits = map dground . scanl (flip dapp) id

相关问题