iterating through a list in haskell

我的梦境 提交于 2020-05-26 16:26:41

问题


I have a list of list of characters ::[[Char]]. I need to iterate both over the list of strings and also over each character in each string.

Say, my list is present in this variable.

let xs

Please suggest an easy way to iterate.


回答1:


If you want to apply a function f to every element of a list like this:

[a, b, c, d] → [f a, f b, f c, f d]

then map f xs does the trick. map turns a function on elements to a function on lists. So, we can nest it to operate on lists of lists: if f transforms as into bs, map (map f) transforms [[a]]s into [[b]]s.

If you instead want to perform some IO action for every element of a list (which is more like traditional iteration), then you're probably looking for forM_:1

forM_ :: [a] -> (a -> IO b) -> IO ()

You give it a function, and it calls it with each element of the list in order. For instance, forM_ xs putStrLn is an IO action that will print out every string in xs on its own line. Here's an example of a more involved use of forM_:

main = do
  ...
  forM_ xs $ \s -> do
    putStrLn "Here's a string:"
    forM_ s print
    putStrLn "Now it's done."

If xs contains ["hello", "world"], then this will print out:

Here's a string:
'h'
'e'
'l'
'l'
'o'
Now it's done.
Here's a string:
'w'
'o'
'r'
'l'
'd'
Now it's done.

1forM_ actually has a more general type, but the simpler version I've shown is more relevant here.




回答2:


The "correct" way to iterate is actually fold. Anything you might ever want to do with a list can be done with a fold. Let's consider what you want to do. You're probably thinking of something like this:

for (row in xs):
  for (c in row):
    doSomething

The problem is, you're probably making use of mutable variables in doSomething. That's ok, we can deal with that. So suppose you have this.

def iter2d(xs):
  outerVar = outerInit
  for (row in xs):
    innerVar = innerInit(row)
    outerVar.adjust1(row)
    for (c in row):
      innerVar.adjust2(c)
      outerVar.adjust3(c, innerVar)
  return outerVar

Let's translate that to folds. And immutability.

iter2d :: [[Char]] -> Something
iter2d xs = foldl' outerStep outerInit xs
  where outerInit = ... -- same as outerInit above
        outerStep acc row = fst $ foldl' innerStep innerInit' row)
          where innerInit' = ((adjust1 acc row), innerInit row)
        innerInit row = ... -- same as innerInit above
        innerStep (outAcc, inAcc) c = (outAcc', inAcc')
          where inAcc' = adjust2 inAcc c
                outAcc' = adjust3 outAcc c inAcc'

Notice with immutability, we are forced to indicate that outAc' depends on inAcc', rather than inAcc, meaning, the "state" of innerVar after it is updated.

Now you might say "wow that Haskell looks way ugly, why would I ever want to use Haskell". Yes, it does look ugly, but only because I tailored it to be a direct translation of imperative code. Once you get used to using folds instead of "iterating through a list", then you will find that folding is a very powerful technique that lets you do a lot of things in a more elegant way than for loops allow.




回答3:


map (map f) l

where f :: Char -> Foo is a function to apply to each Char and l :: [[Char]]
returns l' :: [[Foo]]




回答4:


Just that:

[c | x <- xs, c <- x]


来源:https://stackoverflow.com/questions/9014626/iterating-through-a-list-in-haskell

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!