问题
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 a
s into b
s, 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