Related
I'm trying to make a function that takes the last character from a string and add it to be the first character. In string I can do this (xs:x) and then x is the last character?
xs is just a naming convention for lists in Haskell (which you should use!). (x:xs) is a pattern matching using the (:) function, it is up to you how you name it e.g. (this:makesnosense) is also valid.
Also remember that a String is just another list, so your question is equal to: "How can I make the last element of a list the first one."
This would be one way to solve it:
lastToFirst :: [a] -> [a]
lastToFirst [] = []
lastToFirst [x] = [x]
lastToFirst xs = last xs : init xs
I'm trying to make a function that takes away the last character from a string and add it to be the first character.
In Haskell, list operator ':' is asymmetric. If the left operand is of type α, the right operand must be of type [α]. Hence, a pattern such as xs:x is just using misleading variable names. The operator is right-associative, so that x0:x1:xs means x0:(x1:xs).
Unlike Python lists, which are basically arrays, Haskell lists are just forward-chained linked lists. Classic imperative languages often maintain both a pointer to the head of a linked list and to its tail, but the main point of the tail pointer is to be able to append new elements at the tail of the list.
As Haskell lists are immutable, the tail pointer would be mostly useless, and so Haskell only maintains a pointer to the head of a list.
This means there is no cheap way to access the last element. The only way is to traverse the whole list, starting from the head. Furthermore, immutability implies that the only way to generate the [1,2,3] list from the [1,2,3,4] list is by duplicating the first 3 elements, which again require a full traversal.
So an expression such as last xs : init xs, if compiled naïvely, implies 2 costly traversals of the input list.
The best one can hope is to leverage the duplication work to grab the last element at no extra cost, thus solving the problem in a single traversal. This can be done, for example, by recursion:
makeLastFirst :: [a] -> [a]
makeLastFirst [] = [] -- empty input list
makeLastFirst [end] = [end] -- just the last element
makeLastFirst (x0:(x1:xs)) = let (end:ys) = makeLastFirst (x1:xs)
in end : (x0:ys)
where the recursive clause takes care of keeping the input tail element at the head of the output list.
Watching the gears turn:
One can visualize the recursive process by importing package Debug.Trace and using its trace function. Expression trace msg value evaluates to just value, but has the side effect of printing the msg string. Yes, side effects are normally forbidden in Haskell, but function trace has special privileges.
So we can write a more talkative version of our function:
import Debug.Trace
traceMakeLastFirst :: Show a => [a] -> [a]
traceMakeLastFirst [] = [] -- empty input list
traceMakeLastFirst [end] = [end] -- just the last element
traceMakeLastFirst (x0:(x1:xs)) = let (end:ys) = traceMakeLastFirst (x1:xs)
result = end : (x0:ys)
in trace (show result) result
Testing under the ghci interpreter:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
λ>
λ> :load q66927560.hs
...
Ok, one module loaded.
λ>
λ> traceMakeLastFirst ""
""
λ>
λ> traceMakeLastFirst "a"
"a"
λ>
λ> makeLastFirst "Mercury"
"yMercur"
λ>
λ> traceMakeLastFirst "Mercury"
""yr"
"yur"
"ycur"
"yrcur"
"yercur"
"yMercur"
yMercur"
λ>
-- makeLastFirst "abcd" == "dabc"
-- makeLastFirst "hello" == "ohell"
-- makeLastFirst "orange" == "eorang"
makeLastFirst :: [a] -> [a]
makeLastFirst lst = [ head (reverse lst) ] ++ (init lst)
Are there any practical uses of the list monad that wouldn't just roll to a fmap? When would you use bind over fmap with the list monad?
Like, for example, you can do [1,2,3] >>= return . ( + 1) but that's the same as (+1) <$> [1,2,3] - when would you use bind without a return on list?
Using bind with return is equivalent to using fmap. Indeed,
fmap f m = m >>= return . f
The uses of bind that can't be reproduced with fmap are exactly those which don't involve this use of return. To provide just one (hopefully) interesting example for lists, let's talk about L-Systems.
L-systems were created by Aristid Lindenmeyer in 1968. As rewriting systems, they start with a simple object and repeatedly replace parts of it using a set of rewriting rules or productions. They can be used to generate fractals and other self-similar images. A context-free, deterministic L-System (or D0L) is defined by the triple of an alphabet, an axiom, and a collection of production rules.
For our alphabet, we'll define a type:
data AB = A | B deriving Show
for our axiom, or starting state, we'll use the word [A, B].
myAxiom = [A, B]
For our rules, we need a map from a single letter to a sequence of letters. This is a function of type AB -> [AB]. Let's use this rule:
myRule :: AB -> [AB]
myRule A = [A, B]
myRule B = [A]
To apply the rule, we must rewrite each letter using its production rule. We must do this for all letters in the word at the same time. Conveniently, this is exactly what >>= does for lists:
apply rule axiom = axiom >>= rule
Now, let's apply our rule to our axiom, generating the first step in the L-System:
> apply myRule myAxiom
> [A, B, A]
This is Lindenmeyer's original L-System, used for modeling algae. We can iterate to see it progress:
> mapM_ print . take 7 $ iterate (>>= myRule) myAxiom
[A,B]
[A,B,A]
[A,B,A,A,B]
[A,B,A,A,B,A,B,A]
[A,B,A,A,B,A,B,A,A,B,A,A,B]
[A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A]
[A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,B,A,A,B,A,A,B,A,B,A,A,B,A,A,B]
In general, bind for lists is concatMap, and you use it precisely when you want to combine mapping with concatenation. Another interpretation is that lists represent non-deterministic choice and that bind functions by choosing each possibility from the list once. For example, rolling dice:
do
d1 <- [1..6]
d2 <- [1..6]
return (d1, d2)
This gives all possible ways of rolling 2d6.
factors :: Int -> [Int]
factors n = do
q <- [1..n]
filter ((==n) . (*q)) [1..n]
...or, in desugared notation,
factors n = [1..n] >>= ($[1..n]) . filter . fmap (==n) . (*)
That's of course hardly efficient, but it works:
*Main> factors 17
[17,1]
*Main> factors 24
[24,12,8,6,4,3,2,1]
*Main> factors 34
[34,17,2,1]
For operations that's aren't so simple as *, so you couldn't avoid a brute-force approach like that, this might actually be a good solution.
For one thing, concatMap is just (=<<). And concat is just join. I've used both of these frequently in real code.
Another thing you can do is apply a list of functions to one value.
λ:> applyList = sequence
λ:> applyList [(2*), (3+)] 4
[8,7]
You can also generate a list of all subsets of a list
λ:> import Control.Monad
λ:> allSubsets = filterM (const [True, False])
λ:> allSubsets "ego"
["ego","eg","eo","e","go","g","o",""]
Or even enumerate all strings that can be formed from an alphabet
λ:> import Data.List
λ:> import Control.Monad
λ:> allStrings = sequence <=< (inits . repeat)
λ:> take 100 $ allStrings ['a'..'z']
["","a","b","c","d","e","f","g","h","i","j","k","l","m","n","o","p","q","r","s","t","u","v","w","x","y","z","aa","ab","ac","ad","ae","af","ag","ah","ai","aj","ak","al","am","an","ao","ap","aq","ar","as","at","au","av","aw","ax","ay","az","ba","bb","bc","bd","be","bf","bg","bh","bi","bj","bk","bl","bm","bn","bo","bp","bq","br","bs","bt","bu","bv","bw","bx","by","bz","ca","cb","cc","cd","ce","cf","cg","ch","ci","cj","ck","cl","cm","cn","co","cp","cq","cr","cs","ct","cu"]
Perhaps more practically, you can use the applicative instance to combine two lists together
λ:> zipWith' f xs ys = f <$> xs <*> ys
λ:> zipWith' (+) [1..3] [5..8]
[6,7,8,9,7,8,9,10,8,9,10,11]
I am posting below some code in Haskell. Please treat the code as an example, which I am going to use, to explain what I would like to know.
try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]]
try (a:as) (b:bs) (c:cs) | ((checkIfCorrect a b c) == True) = a:b:[c]
| otherwise = try as bs cs
checkIfCorrect :: [Char] -> [Char] -> [Char] -> Bool
checkIfCorrect a b c = True
Eventually, checkIfCorrect returns True for only one combination of arguments. checkIfCorrect is really long function, so I decided to post substitute here. In the example above, function checkIfCorrect is applicated (by function try) to: first [Char] on the first list, first [Char] on the second list and first [Char] one the third list. If first guarded equation is not fulfilled, function checkIfCorrect is applied to: second [Char] on the first list ... and so on. What I would like to reach, is to applicate function checkIfCorrect (by function try) to all combinations of [Char]s from all lists
([[Char]] ). I mean the following (e.g.): third [Char] on the first list, eighth [Char] on the second list, eleventh [Char] on the third list and so on. Everyone with everyone. How could I easy reach that?
I just wanted to show you an alternative way of writing #WillemVanOnsem's code. I'm guessing that you're a Haskell beginner, so hopefully this answer will give you a tiny glimpse of a rich and beautiful idea which you'll soon be learning about in full as you progress with the language. So don't worry too much if you don't understand everything about this code right away; I'm just trying to give you a taste!
A list comprehension can always be reformulated using the list monad:
import Control.Monad (guard)
try as bs cs = head $ do
a <- as
b <- bs
c <- cs
guard $ checkIfCorrect a b c
return [a,b,c]
I'm using do notation as a special notation for nested loops: for each a in as, for each b in bs, and for each c in cs, we yield [a,b,c] if checkIfCorrect returns True. The translation from list comprehensions is simple: "enumeration" parts of the list comprehension turn into "binds" using <-, "filter"s turn into calls to guard, and "yield"s turn into returns.
In an imperative language like Python you might write it like this:
def try(as, bs, cs):
for a in as:
for b in bs:
for c in cs:
if checkIfCorrect(a, b, c):
yield [a,b,c]
Like politics under the Western neoliberal hegemony, the imperative code gradually marches rightward. "Staircase" code like this actually crops up quite frequently in imperative programming (think of "callback hell" in JS), so monads were invented to help counteract this tendency. They turned out to be so useful that a special syntax was invented for them, namely do-notation.
Yes, you can make it also look more elegant with list comprehension:
try :: [[Char]] -> [[Char]] -> [[Char]] -> [[Char]]
try as bs cs = head [ [a,b,c] | a <- as, b <- bs, c <- cs, checkIfCorrect a b c ]
-- \__ __/ \__________ ____________/ \__________ _______/
-- v v v
-- yield enumeration filter
The code works as follows: the right part of the list comprehension consists out of an "enumeration" part (denoted by the comment section). Since we write a <- as, b <- bs, c <- cs it means that a will take any value from as, and for every such a, b will take any value of bs, etc. So that means every possible combination will be emitted.
Next there is the "filter" phase: there is a predicate checkIfCorrect a b c that will be called and only if that predicate returns True, the result will be "yielded".
On the left side we see "yield". It describes what to add to the list (based on the enumeration) given the filter succeeds. If that happens we add [a,b,c] to that list. If there are multiple such configurations that succeed, we might end up with a list containing multiple solutions. Note however that list comprehension is done lazily: so as long as you do not ask for at least one such element, it will not generate the first element, nor the second, etc.
Now we also need head (in front of the list comprehension). head :: [a] -> a returns the first element of the list. So try will return the first element that satisfies the condition.
While both Willem Van Onsem's and The Orgazoid's answers are good (upvoted), you can also approach part of the problem in a more generalised way, and not only for lists.
For the following, you're going to need these imports:
import Control.Monad (MonadPlus, mfilter)
import Data.Maybe (fromMaybe, listToMaybe)
If I'm understanding the question correctly, you want to try all combinations of as, bs, and cs. You can typically achieve combination-like behaviour with the Applicative typeclass:
combinations = (,,) <$> as <*> bs <*> cs
(,,) is a function that creates triples (three-element tuples) from three individual values.
This works for lists, because lists are applicative:
*Prelude> (,,) <$> [1,2] <*> ["foo", "bar"] <*> [True, False]
[(1,"foo",True),(1,"foo",False),(1,"bar",True),(1,"bar",False),(2,"foo",True),(2,"foo",False),(2,"bar",True),(2,"bar",False)]
but it also works for e.g. Maybes:
*Prelude> (,,) <$> Just 1 <*> Just "foo" <*> Just False
Just (1,"foo",False)
With that, you can now define the core of your function:
try' :: MonadPlus m => ((a, a, a) -> Bool) -> m a -> m a -> m a -> m [a]
try' predicate as bs cs =
tripleToList <$> mfilter predicate combinations
where
combinations = (,,) <$> as <*> bs <*> cs
tripleToList (a, b, c) = [a, b, c]
You'll notice that this helper function is completely generic. It works for any MonadPlus instance of any contained element a.
Here are some examples:
*Answer> try' (const True) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"]
[["foo","qux","grault"],["foo","qux","garply"],["foo","quux","grault"],["foo","quux","garply"],["foo","quuz","grault"],["foo","quuz","garply"],["foo","corge","grault"],["foo","corge","garply"],["bar","qux","grault"],["bar","qux","garply"],["bar","quux","grault"],["bar","quux","garply"],["bar","quuz","grault"],["bar","quuz","garply"],["bar","corge","grault"],["bar","corge","garply"],["baz","qux","grault"],["baz","qux","garply"],["baz","quux","grault"],["baz","quux","garply"],["baz","quuz","grault"],["baz","quuz","garply"],["baz","corge","grault"],["baz","corge","garply"]]
*Answer> try' (const False) ["foo", "bar", "baz"] ["qux", "quux", "quuz", "corge"] ["grault", "garply"]
[]
*Answer> try' (const True) (Just "foo") (Just "bar") (Just "baz")
Just ["foo","bar","baz"]
*Answer> try' (const False) (Just "foo") (Just "bar") (Just "baz")
Nothing
You should notice that if predicate always returns False, you'll get nothing back. For lists, you get the empty list; for Maybe, you literally get Nothing.
So far it's all generic, but checkIfCorrect isn't. It also looks like you'd like to get only the first elements that match. You can achieve that by composing try' with checkIfCorrect:
try :: [String] -> [String] -> [String] -> [String]
try as bs cs = fromMaybe [] $ listToMaybe $ try' isCorrect as bs cs
where isCorrect (a, b, c) = checkIfCorrect a b c
Here, I've created a private isCorrect function in order to uncurry the checkIfCorrect function. I've then used a combination of listToMaybe and fromMaybe to return the first element of the resulting list. Other answers here use head, but that's going to throw an exception if the list is empty, so I used this combination instead, because it's safe.
I am trying to generate a list of all strings that consist of 6 Xs and 3 Qs.
A subset of the list I am trying to generate is as follows:
["XXXXXXQQQ", "XQXXQXXQX", "QXQXQXXXX",...
What is a good way to go about this?
Here is a dynamic programming solution using Data.Array. mem just stores memoized values.
import Data.Array
strings :: Int -> Int -> [String]
strings n m = strings' n m
where
mem :: Array (Int,Int) [String]
mem = array ((0,0),(n,m)) [ ((i,j), strings' i j) | i <- [0..n], j <- [0..m] ]
strings' 0 m = [replicate m 'X']
strings' n 0 = [replicate n 'Q']
strings' n m = (('Q':) <$> mem ! (n-1,m)) ++ (('X':) <$> mem ! (n,m-1))
The naive solution is to recursively choose one of X or Q until we run out of choices to make. This is especially convenient when using the list monad to model the nondeterministic choice, and leads to quite short code:
stringsNondet m 0 = [replicate m 'X']
stringsNondet 0 n = [replicate n 'Q']
stringsNondet m n = do
(char, m', n') <- [('X', m-1, n), ('Q', m, n-1)]
rest <- stringsNondet m' n'
return (char:rest)
The disadvantage of this approach is that it does a lot of extra work. If we choose an X and then choose a Q, the continuations are the same as if we had chosen a Q and then an X, but these continuations will be recomputed in the above. (And similarly for other choice paths that lead to shared continuations.)
Alec has posted a dynamic programming solution which solves this problem by introducing a recursively-defined array to share the subcomputations. I like this solution, but the recursive definition is a bit mind-bending. The following solution is also a dynamic programming solution -- subcomputations are also shared -- but uses no hand-written recursion. It does make use of standard recursive patterns (map, zip, iterate, ++, and !!) but notably does not require "tying the knot" as Alec's solution does.
As a warmup, let's discuss the type of the function of interest to us:
step :: [[String]] -> [[String]]
The final result of interest to us is [String], a collection of strings with a fixed number m of 'X's and a fixed number n of 'Q's. The step function will expect a collection of results, all of the same length, and will assume that the result at index m has m copies of 'X'. It will also produce a result with these properties, and where each result is one longer than the input results.
We implement step by producing two intermediate [[String]]s, one with an extra 'X' compared to the input results and one with an extra 'Q'. These two intermediates can then be zipped together with a little "stutter" to represent the slight difference in 'X' count between them. Thus:
step css = zipWith (++)
([[]] ++ map (map ('X':)) css)
(map (map ('Q':)) css ++ [[]])
The top-level function is now easy to write: we simply index into the iterated version of step by the length of the final string we want, then index into the list of results we get that way by the number of 'X's we want.
strings m n = iterate step [[[]]] !! (m+n) !! m
A bonus of this approach is the single, aesthetically pleasing base case of [[[]]].
Use permutations and nub functions from Data.List:
Prelude Data.List> nub $ permutations "XXXXXXQQQ"
["XXXXXXQQQ","QXXXXXXQQ","XQXXXXXQQ","XXQXXXXQQ","XXXQXXXQQ","XXXXQXXQQ","XXXXXQXQQ","QQXXXXXXQ","QXQXXXXXQ","QXXQXXXXQ","QXXXQXXXQ","QXXXXQXXQ","QXXXXXQXQ","XQQXXXXXQ","XQXQXXXXQ","XQXXQXXXQ","XQXXXQXXQ","XQXXXXQXQ","XXQQXXXXQ","XXQXQXXXQ","XXQXXQXXQ","XXQXXXQXQ","XXXQQXXXQ","XXXQXQXXQ","XXXQXXQXQ","XXXXQQXXQ","XXXXQXQXQ","XXXXXQQXQ","QQQXXXXXX","QQXQXXXXX","QQXXQXXXX","QQXXXQXXX","QQXXXXQXX","QQXXXXXQX","QXQQXXXXX","XQQQXXXXX","XQQXQXXXX","XQQXXQXXX","XQQXXXQXX","XQQXXXXQX","QXQXQXXXX","QXQXXQXXX","QXQXXXQXX","QXQXXXXQX","QXXQQXXXX","XQXQQXXXX","XXQQQXXXX","XXQQXQXXX","XXQQXXQXX","XXQQXXXQX","XQXQXQXXX","XQXQXXQXX","XQXQXXXQX","QXXQXQXXX","QXXQXXQXX","QXXQXXXQX","QXXXQQXXX","XQXXQQXXX","XXQXQQXXX","XXXQQQXXX","XXXQQXQXX","XXXQQXXQX","XXQXQXQXX","XXQXQXXQX","XQXXQXQXX","XQXXQXXQX","QXXXQXQXX","QXXXQXXQX","QXXXXQQXX","XQXXXQQXX","XXQXXQQXX","XXXQXQQXX","XXXXQQQXX","XXXXQQXQX","XXXQXQXQX","XQXXXQXQX","QXXXXQXQX","XXQXXQXQX","QXXXXXQQX","XQXXXXQQX","XXQXXXQQX","XXXQXXQQX","XXXXQXQQX","XXXXXQQQX"]
We can have a faster implementation as well:
insertAtEvery x [] = [[x]]
insertAtEvery x (y:ys) = (x:y:ys) : map (y:) (insertAtEvery x ys)
combinations [] = [[]]
combinations (x:xs) = nub . concatMap (insertAtEvery x) . combinations $ xs
Comparison with the previous solution in ghci:
Prelude Data.List> (sort . nub . permutations $ "XXXXXXQQQ") == (sort . combinations $ "XXXXXXQQQ")
True
Prelude Data.List> :set +s
Prelude Data.List> combinations "XXXXXXQQQ"
["XXXXXXQQQ","XXXXXQXQQ","XXXXXQQXQ","XXXXXQQQX","XXXXQXXQQ","XXXXQXQXQ","XXXXQXQQX","XXXXQQXXQ","XXXXQQXQX","XXXXQQQXX","XXXQXXXQQ","XXXQXXQXQ","XXXQXXQQX","XXXQXQXXQ","XXXQXQXQX","XXXQXQQXX","XXXQQXXXQ","XXXQQXXQX","XXXQQXQXX","XXXQQQXXX","XXQXXXXQQ","XXQXXXQXQ","XXQXXXQQX","XXQXXQXXQ","XXQXXQXQX","XXQXXQQXX","XXQXQXXXQ","XXQXQXXQX","XXQXQXQXX","XXQXQQXXX","XXQQXXXXQ","XXQQXXXQX","XXQQXXQXX","XXQQXQXXX","XXQQQXXXX","XQXXXXXQQ","XQXXXXQXQ","XQXXXXQQX","XQXXXQXXQ","XQXXXQXQX","XQXXXQQXX","XQXXQXXXQ","XQXXQXXQX","XQXXQXQXX","XQXXQQXXX","XQXQXXXXQ","XQXQXXXQX","XQXQXXQXX","XQXQXQXXX","XQXQQXXXX","XQQXXXXXQ","XQQXXXXQX","XQQXXXQXX","XQQXXQXXX","XQQXQXXXX","XQQQXXXXX","QXXXXXXQQ","QXXXXXQXQ","QXXXXXQQX","QXXXXQXXQ","QXXXXQXQX","QXXXXQQXX","QXXXQXXXQ","QXXXQXXQX","QXXXQXQXX","QXXXQQXXX","QXXQXXXXQ","QXXQXXXQX","QXXQXXQXX","QXXQXQXXX","QXXQQXXXX","QXQXXXXXQ","QXQXXXXQX","QXQXXXQXX","QXQXXQXXX","QXQXQXXXX","QXQQXXXXX","QQXXXXXXQ","QQXXXXXQX","QQXXXXQXX","QQXXXQXXX","QQXXQXXXX","QQXQXXXXX","QQQXXXXXX"]
(0.01 secs, 3,135,792 bytes)
Prelude Data.List> nub $ permutations "XXXXXXQQQ"
["XXXXXXQQQ","QXXXXXXQQ","XQXXXXXQQ","XXQXXXXQQ","XXXQXXXQQ","XXXXQXXQQ","XXXXXQXQQ","QQXXXXXXQ","QXQXXXXXQ","QXXQXXXXQ","QXXXQXXXQ","QXXXXQXXQ","QXXXXXQXQ","XQQXXXXXQ","XQXQXXXXQ","XQXXQXXXQ","XQXXXQXXQ","XQXXXXQXQ","XXQQXXXXQ","XXQXQXXXQ","XXQXXQXXQ","XXQXXXQXQ","XXXQQXXXQ","XXXQXQXXQ","XXXQXXQXQ","XXXXQQXXQ","XXXXQXQXQ","XXXXXQQXQ","QQQXXXXXX","QQXQXXXXX","QQXXQXXXX","QQXXXQXXX","QQXXXXQXX","QQXXXXXQX","QXQQXXXXX","XQQQXXXXX","XQQXQXXXX","XQQXXQXXX","XQQXXXQXX","XQQXXXXQX","QXQXQXXXX","QXQXXQXXX","QXQXXXQXX","QXQXXXXQX","QXXQQXXXX","XQXQQXXXX","XXQQQXXXX","XXQQXQXXX","XXQQXXQXX","XXQQXXXQX","XQXQXQXXX","XQXQXXQXX","XQXQXXXQX","QXXQXQXXX","QXXQXXQXX","QXXQXXXQX","QXXXQQXXX","XQXXQQXXX","XXQXQQXXX","XXXQQQXXX","XXXQQXQXX","XXXQQXXQX","XXQXQXQXX","XXQXQXXQX","XQXXQXQXX","XQXXQXXQX","QXXXQXQXX","QXXXQXXQX","QXXXXQQXX","XQXXXQQXX","XXQXXQQXX","XXXQXQQXX","XXXXQQQXX","XXXXQQXQX","XXXQXQXQX","XQXXXQXQX","QXXXXQXQX","XXQXXQXQX","QXXXXXQQX","XQXXXXQQX","XXQXXXQQX","XXXQXXQQX","XXXXQXQQX","XXXXXQQQX"]
(0.71 secs, 161,726,128 bytes)
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.
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.
1 forM_ actually has a more general type, but the simpler version I've shown is more relevant here.
Just that:
[c | x <- xs, c <- x]
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.
map (map f) l
where f :: Char -> Foo is a function to apply to each Char and l :: [[Char]]
returns l' :: [[Foo]]