在Haskell中的2dimentional列表上使用foldl

时间:2014-11-16 23:30:44

标签: list haskell fold

我正在尝试实现一个以bfs顺序收集OrdTree中所有值的函数,而且我也很难用它。以下是我到目前为止所提供的内容:

data OrdTree a = OrdTree a [OrdTree a]  deriving (Show)

bfsTree ::  OrdTree a ->  [a]
bfsTree tree = 
    let 
        use2DList level list (OrdTree a []) = (list!!level)++[a]
        use2DList currentLevel list (OrdTree a (branches)) =
            foldl 
                (\tree theList -> use2DList (currentLevel+1) theList tree) 
                ((list!!currentLevel)++[a]) 
                branches 
    in 
        concat (use2DList 0 [] tree)

显然我遇到了一堆我未能弄明白的错误。

  1. 我认为既然它似乎在范围内,我应该可以在foldl中使用currentLevel变量(特别是在匿名函数中),我也是吗?这样可以吗?或者它只需要使用->左侧指定的操作数?
  2. 我知道东西是不可变的,但是列表列表..如果我将一个值附加到列表中的一个列表中,它会改变它,对吧?但是这些代码会返回什么:(list!!position)++[value]
  3. 如果我试着像这样(如果我做对了)那会更好吗:
    foldl (use2DList (currentLevel+1)) (list!!currentLevel)++[a]) branches还是更糟糕?
  4. 对不起,如果文字太多,我真的很困惑这个东西。

1 个答案:

答案 0 :(得分:1)

这是bfs命令的意思吗?

val (OrdTree a _) = a
children (OrdTree _ ts) = ts

bfs :: [OrdTree a] -> [a]
bfs ts = (map val ts) ++ bfs (concatMap children ts)

请注意,我已撰写bfs来获取Ordtree a的列表,而不仅仅是一棵树。

  • bfs的参数是当前级别的树列表。
  • map val ts是当前级别的值
  • concatMap children ts是下一级别的所有树

更新:以下是我对您的代码所做的一些分析。

首先它没有编译,所以我开始删除代码,直到编译器停止抱怨,我到达:

data OrdTree a = OrdTree a [OrdTree a]  deriving (Show)

bfsTree tree =
      let
          use2DList level list (OrdTree a []) = [a] ++ (list!!level)
      in concat (use2DList 0 [] tree)

请注意bfsTree上没有类型签名 - 我们将告诉我们签名是什么,它会回复:

bfsTree :: OrdTree [a] -> [a]

这显然不对 - 我们想要OrdTree a -> [a]。事实证明,罪魁祸首是concat,所以显然代码应该是:

bfsTree tree =
      let
          use2DList level list (OrdTree a []) = [a] ++ (list!!level)
      in use2DList 0 [] tree

现在我们可以问use2DList的类型签名是什么,ghc(真正的ghc-mod)响应:

use2DList :: Int -> [[a]] -> OrdTree a -> [a]

现在我们必须弄明白foldl应该是什么。 foldl有签名:

foldl :: (s -> t -> s) -> s -> [t] -> s

显然我们折叠分支,即t ~ OrdTree ause2DList的返回类型是[a],所以s ~ [a],所以{{1}的第一个参数应该看起来像:

foldl

由于您的函数开始(\listofa tree -> ...) ,看起来您必须交换参数。而且就我而言。

主要建议是:

  • 使用GHC和类型系统来帮助您发现错误;为所有定义添加类型签名 - 包括帮助函数
  • 学习使用ghci中的(\tree theList -> ...)命令来查询推断的函数类型
  • 使用vim的:t插件或emacs的haskell-mode插件,以便查询程序中的子表达式