使用foldr Haskell反转列表

时间:2017-10-13 09:51:52

标签: list haskell fold

我正在尝试使用foldr来反转Haskell中的列表列表。有一个我想做的例子:

> reverse'' [[1,2,3],[3,4,5]]
[[5,4,3],[3,2,1]]

我的代码(它没有用):

reverse'':: [[a]]->[[a]]
reverse'' x = foldr (\n acum -> acum:(foldr(\m acum1 -> acum1++[m])) [] n) [[]] x

我的IDE在第二个折叠开始时报告错误。

1 个答案:

答案 0 :(得分:2)

为了分析你当前的解决方案,我已经将你的单行分解为一些辅助功能,其类型根据其组成推断:

reverse'':: [[a]] -> [[a]]
reverse'' x = foldr f [[]] x
    where
        f :: [a] -> a -> [a]
        f n acum = acum : reverse n

        reverse :: [a] -> [a]
        reverse n = foldr append [] n

        append :: a -> [a] -> [a]
        append m acum = acum ++ [m]

当我尝试编译上面的内容时,ghc对reverse''的类型签名抱怨以下错误:

Expected type: [[a]] -> [[a]] -> [[a]]
  Actual type: [[a]] ->  [a]  -> [[a]]

我做了一些挖掘,为了使reverse''具有[[a]] -> [[a]]类型,函数f需要具有类型[a] -> [[a]] -> [[a]]。但是,当前的f类型为[a] -> a -> [a],在这种情况下为[[a]] -> [a] -> [[a]]

以下具有正确的类型,但由于累加器的起始值,在数组的开头插入额外的[]值:

reverse'':: [[a]] -> [[a]]
reverse'' x = foldr f [[]] x
    where
        f :: [a] -> [[a]] -> [[a]]
        f n acum = acum ++ [reverse n]

        reverse :: [a] -> [a]
        reverse n = foldr append [] n

        append :: a -> [a] -> [a]
        append m acum = acum ++ [m]

最终解决方案

通过将初始累加器值更改为空列表[],而不是空列表[[]]的列表,我们最终得到了一个可行的解决方案:

reverse'':: [[a]] -> [[a]]
reverse'' x = foldr f [] x
    where
        f :: a -> [a] -> [a]
        f n acum = acum ++ [reverse n]

        reverse :: [a] -> [a]
        reverse n = foldr append [] n

        append :: a -> [a] -> [a]
        append m acum = acum ++ [m]

作为单行

如果你真的想要这个作为一个单行,那么它是:

reverse'' :: [[a]] -> [[a]]
reverse'' = foldr (\n acum -> acum ++ [foldr (\m acum1 -> acum1 ++ [m]) [] n]) []

工作:

append m acum = acum ++ [m]
append = \m acum1 -> acum1 ++ [m]

reverse n = foldr append [] n
reverse = \n -> foldr append [] n
reverse = foldr append []
reverse = foldr (\m acum1 -> acum1 ++ [m]) []

f n acum = acum ++ [reverse n]
f = \n acum -> acum ++ [reverse n]
f = \n acum -> acum ++ [foldr (\m acum1 -> acum1 ++ [m]) [] n]

reverse'':: [[a]] -> [[a]]
reverse'' x = foldr f [] x
reverse'' x = foldr (\n acum -> acum ++ [foldr (\m acum1 -> acum1 ++ [m]) [] n]) [] x
reverse'' = foldr (\n acum -> acum ++ [foldr (\m acum1 -> acum1 ++ [m]) [] n]) []

附录:明确的递归解决方案

这是一个明确的递归解决方案(即不使用fold),提供了mapreverse的定义。

reverse :: [a] -> [a]
reverse (x:xs) = reverse xs ++ [x]
reverse []     = []

map :: (a -> b) -> [a] -> [b]
map f (x:xs) = f x : map f xs
map _ [] = []

reverse'' :: [[a]] -> [[a]]
reverse'' ls = reverse $ map reverse ls