I am making the pilgrimage from Java to Haskell. Broadly speaking, I get the main concepts behind Haskell. Reading all the tutorials and books 'makes sense' but I am getting stuck writing my own code from scratch.
I want to create 1000 files on the file system with names
"myfile_1.txt" ... "myfile_1000.txt"
and each containing some dummy text.
so far I have worked out the whole IO thing, and realise I need to build a list of Strings 1000 elements long. So I have:
buildNamesList :: [] -> []
buildNamesList ???
Once I have the List I can call the writefile method on each element. What I can't figure out is how to add a number to the end of a String to get each fileName because I can't have an int i = 0, i ++ construct in Haskell.
I am a bit out of my depth here, would appreciate some guidance, thanks
One possible solution:
buildNamesList = map buildName [1..1000]
where buildName n = "myfile_" ++ show n ++ ".txt"
import Control.Applicative
fileNames = ("myFile_"++) <$> (++".txt") <$> show <$> [1..1000]
how do I then traverse over it, pluck out the String at element n and then pass it into another function?
No! "Plucking out" something from a list in inefficient. You don't want to worry about how to get to each element, then do something with it. That's necessary in imperative languages because they don't have a proper abstraction over what "sequencing actions" means – it's just something magical built into the language. Haskell has much more well-specified, mathematically sound and type-safe magic for that; as a result you don't need loops and suchlike.
You know what to do with each element (String -> IO ()), and you know where the data comes from ([String]). You also know what should eventually happen (IO ()). So the combinator you're looking for has type ( String -> IO() ) -> [String] -> IO (), though obviously it doesn't really depend on the data being Strings, so let's simplify that to (a -> IO()) -> [a] -> IO(). You can look that up on Hoogle, which offers amongst sume rubbish mapM_ and forM_, both of which do what you want:
mapM_ (\filename -> writeFile filename "bla") filenamesList
or
forM_ filenamesList $ \filename ->
writeFile filename "bla"
Sometimes I think of foldr as bearing some resemblance to a for loop. Here's something kind of like the i++ construct, applying i inside a loop:
foldr (\i accum -> ("myfile_" ++ show i ++ ".txt") : accum) [] [1..1000]
Another way could be zipWith, which applies a function to combine two lists:
zipWith (\a b -> a ++ show b ++ ".txt") (repeat "myfile_") [1..1000]
or
zipWith ($) (repeat (("myfile_" ++) . (++ ".txt") . show)) [1..1000]
And here's a recursive example, too, applied as fileList "myfile_" ".txt" [1..1000]:
fileList _ _ [] = []
fileList fName ext (x:xs) = (fName ++ show x ++ ext) : fileList fName ext xs
Related
I want to have a function that reads arbitrary int's until the number '0' is inserted, and then presents the numbers inserted in an ordered list.
For that i wrote this function:
import Data.List
readIntegers :: IO()
readIntegers = do
putStrLn "insert a number: "
num<-getLine
let list = ordList ((read num :: Int):list)
if (read num == 0)
then print list
else readIntegers
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
This compiles just fine, but when i insert the number '0', it gives me this error:
*** Exception: <<loop>>
What am i doing wrong ?
As #phg points out, you are essentially constructing an infinite list, and actually evaluating it causes the loop error. A simple implementation to resolve this issue is to define a helper function which takes an additional parameter - a list to store all the inputs read in from the screen, like so:
readInteger :: IO ()
readInteger = readInteger' []
where
readInteger' x = do
putStrLn "insert a number: "
num<-getLine
if ((read num :: Int) == 0)
then print $ ordList x
else readInteger' $ (read num :: Int):x
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Please note that the above is essentially just an implementation of #phg's answer, but with some changes to your original logic. Firstly, since 0 is a sentinel value, we shouldn't be appending that to our list. Second, we do not need to sort the list every single time we are adding a value to it. Sorting once at the time of printing/passing to another function is sufficient.
Demo
If you want to read an unspecified number of integers without prompting for user input and cut it off the moment you encounter 0, you would probably do well to use getContents, which will read everything from the standard input as a single string, lazily.
Then, it is a simple matter of parsing it to a list of numbers and doing what you want with it, like so:
readIntegers :: ()
readIntegers = do
a <- getContents
let b = ordList $ takeWhile (/= 0) $ map (\x -> read x :: Int) $ words a
mapM (putStrLn . show) b
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
let list = ordList ((read num :: Int):list)
This is basically a recursive definition of a list of the form [x, x, ...] (like if you wrote an equation saying x = 1 + x). That is perfectly fine by itself, since Haskell is lazy; however, if you try to print list (aka "solve the equation"), it will fail, since it will try to print infinitely many numbers.
You probably have a misconception about the workings of the (:) operator. Haskell functions will never perform an assignment operation and concatenate num onto list by changing it, like in imperative languages. There are only pure functions.
If you want to accumulate all numbers, you should try to come up with a recursive definition of readIntegers, keeping its state (the list) in an additional parameter (there are also more sophisticated ways, hiding the state passing, but more complicated to use for a beginner).
For a more sophisticated solution, note that this is an unfold and you can use unfoldM from Control.Monad.Loops to implement it:
import Control.Monad.Loops (unfoldM)
readInts :: IO [Int]
readInts = unfoldM $ fmap (check . read) getLine
where check x = if x == 0 then Nothing else Just x
This has the nice property that it returns the list in the order in which it was read.
I wanted to split a string on newlines and I was surprised that I could not find the inverse function to intercalate "\n". That is, a function that splits a string into pieces on new lines (or according to some other predicate).
Note that lines and words do something different. For example
intercalate "\n" (lines "a\n") == "a"
There is a similar function function splitOn in the split library. I could also write such a function myself directly:
splitOn :: (a -> Bool) -> [a] -> [[a]]
splitOn p = map reverse . g []
where
g rs [] = [rs]
g rs (x:xs) | p x = rs : g [] xs
| otherwise = g (x : rs) xs
but I wonder if it could be constructed more easily using only functions from base.
As Nikita Volkov points out, the restriction "only Prelude functions" doesn't make it very easy, but here's one option:
splitWhen p [] = [[]]
splitWhen p l = uncurry (:) . fmap (splitWhen p . drop 1) . break p $ l
This uses the Functor instance for (,) a as an alternative to Control.Arrow.second (to avoid a messier lambda expression), which works without importing anything (ghci says "defined in 'GHC.Base'"), but I'm not sure if that actually belongs in the Prelude, since I can't find it in the Haskell Report.
Edit: Being allowed to use other functions from base doesn't even help me that much. In any case I would use second instead of fmap because I think it adds a little clarity. With unfoldr, using a Maybe for the seed to distinguish the end of the string from an empty part (or empty line in the example):
import Control.Applicative ((<$>))
import Control.Arrow (second)
import Data.List (unfoldr)
splitWhen p = unfoldr (second check . break p <$>) . Just
where
check [] = Nothing
check (_:rest) = Just rest
-- or cramming it into a single line with 'Data.Maybe.listToMaybe'
splitWhen' p =
unfoldr (second (\rest -> tail rest <$ listToMaybe rest) . break p <$>) . Just
If the composition of more primitive functions is what you're looking for, then I can think of no other way than something based on unfoldr and break, but unfoldr is not in Prelude.
Anyway, I think you're well aware that Prelude is far from what many of us want it to be, so there's no surprise that it can't solve even such a seemingly trivial problem. The general problem with Prelude seems to be that it's mispurposed: the module aims to provide things that are enough to play with Haskell as part of an introduction, as even its name suggests, but since there is no standard "base" module, Haskellers tend to see it as one.
we started a paper on Haskell a few weeks ago and just received our first assignment. I'm aware that SO doesn't like homework questions, so I'm not going to ask how to do it. Instead, it would be very much appreciated if anyone could push me in the right direction with this. Seeing as it might not be a specific question, would it be more appropriate in a discussion / community wiki?
Question: Tokenize a String, that is: "Hello, World!" -> ["Hello", "World"]
Coming from a Java background, I have to forget everything about the usual way to go about this. The problem is that I am still very clueless with Haskell. This is what I've come up with:
module Main where
main :: IO()
main = do putStrLn "Type in a string:\n"
x <- getLine
putStrLn "The string entered was:"
putStrLn x
putStrLn "\n"
print (tokenize x)
tokenize :: String -> [String]
tokenize [] = []
tokenize l = token l ++ tokenize l
token :: String -> String
token [] = []
token l = takeWhile (isAlphaNum) l
What would be the first glaring mistake?
Thank you.
The first glaring mistake is
tokenize l = token l ++ tokenize l
(++) :: [a] -> [a] -> [a] appends two lists of the same type. Since token :: String -> String (and type String = [Char]), the type of tokenize that is inferred from that line is tokenize :: String -> String.
You should use (:) :: a -> [a] -> [a] here.
The next mistake in that line is that in the recursive call, you pass the same input l once again, so you have an infinite recursion, always doing the same without change. You have to remove the first token (and a bit more) from the input for the argument to the recursive call.
Another problem is that your token supposes that the input begins with alphanumeric characters.
You also need a function that ensures that condition for what you pass to token.
This line results in an infinite list (which is OK, since Haskell is lazy, so the list only gets constructed "on demand"), because it is recurring with no change in the arguments:
tokenize l = token l ++ tokenize l
We can visualise what is happening when tokenize is called as:
tokenize l = token l ++ tokenize l
= token l ++ (token l ++ tokenize l)
= token l ++ (token l ++ (token l ++ tokenize l))
= ...
To stop this happening, you need to change what the argument to tokenize so that it recurs sensibly:
tokenize l = token l ++ tokenize <something goes here>
As others already pointed out your mistake, just a little hint: While you found already the very useful takeWhile function, you should have a look at span, as this could be even more helpful here.
This has something in it that feels similar to a parser monad. However, as you're a newcomer to Haskell, it's unlikely that you're in a position to understand how parsing monads work (or use them in your code) quite yet. To give you the basics, consider what you want:
tokenize :: String -> [String]
This takes a String, chomps it up into more pieces, and generates a list of strings corresponding to the words in the input string. How might we represent this? What we want to do is find a function that processes a single string, and at the first sign of whitespace, adds that string on to the sequence of words. But then you have to process what's left over. (I.e., the rest of the string.) For example, let's say you want to tokenize:
The brown fox jumped
You first pull out "The" and then continue processing " brown fox jumped" (note the space at the beginning of the second string). You will do this recursively, so naturally you will need a recursive function.
The natural solution that sticks out is to take something where you accumulate a set of strings you've tokenized so far, keep munching on the current input until you hit whitespace, then also accumulate what you've seen in the current string (this leads to an implementation where you're mostly consing stuff, and then occasionally reversing stuff).
Your exercise seemed a bit challenging to me so I decided to solve it just for self-training. Here's what I came up with:
import Data.List
import Data.Maybe
splitByAnyOf yss xs =
foldr (\ys acc -> concat $ map (splitBy ys) acc) [xs] yss
splitBy ys xs =
case (precedingElements ys xs, succeedingElements ys xs) of
(Just "", Just s) -> splitBy ys s
(Just p, Just "") -> [p]
(Just p, Just s) -> p : splitBy ys s
otherwise -> [xs]
succeedingElements ys xs =
fromMaybe Nothing . find isJust $ map (stripPrefix ys) $ tails xs
precedingElements ys xs =
fromMaybe Nothing . find isJust $ map (stripSuffix ys) $ inits xs
where
stripSuffix ys xs =
if ys `isSuffixOf` xs then Just $ take (length xs - length ys) xs
else Nothing
main = do
print $ splitBy "!" "Hello, World!"
print $ splitBy ", " "Hello, World!"
print $ splitByAnyOf [", ", "!"] "Hello, World!"
outputs:
["Hello, World"]
["Hello","World!"]
["Hello","World"]
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]]
Basically what I need to do is write a function that takes in a list of type [(String, String)] and prints out the contents so that, line-by-line, the output looks like this:
FirstString : SecondString
FirstString : SecondString
..etc, for every item in the list. I've got the following code and it prints it out, but for some reason it prints out a line containing [(),()] at the end.
display :: Table -> IO ()
display zs = do {
xs <- sequence [putStrLn ( a ++ " = " ++ b) | (a, b) <- zs];
print xs
}
Is there anything I'm doing wrong?
The final print xs is unnecessary. sequence here is returning a bunch of ()s (the return value of putStrLn), and print is printing that out as well.
While you're at it, now that print xs is gone, you can get rid of the xs variable binding, and make sequence into sequence_ to throw away the return value, giving:
display :: Table -> IO()
display zs = sequence_ [putStrLn (a++" = "++b) | (a,b) <- zs]
You could even use mapM:
display :: Table -> IO ()
display = mapM_ (\(a,b) -> putStrLn (a++" = "++b))
I would agree with ja that you should split up your code in to two functions:
A pure part: a function that takes your data structure and turns it into a string
An impure part, that renders that string to the console
Here's a simple implementation:
showTable :: Table -> String
showTable xs = concatMap format xs
where
format (a, b) = a ++ " : " ++ b ++ "\n"
display :: Table -> IO ()
display table = putStr (showTable table)
This design has two advantages:
For one, most of your `logic' is in the pure part of the code, which is nice, in a functional programming kind of way.
Secondly, and this is just simple software engineering principle; you now have a reusable function that you can use, should you ever want to format your data structure in another part of your code (seems likely).
Write a function that takes a tuple to a string, formatted as you wish.
Then concatMap that function over your list; print the result.