Haskell String to List of Strings using Words - string

I'm rather new to Haskell, and I'm currently using LearnYouAHaskell.
I am trying to take a string separated by white space, and break it into a list of smaller word strings.
My current program:
main = do
putStrLn "Insert a string to convert: "
-- Input string
line <- getLine
words line;
But in this case, it tells me I'm having an IO error.
TO my understanding, getLine is an action, and so since this is impure, I have to bind it to "line". Line is an accurate representation of getLine, which is an IO String.
However, shouldn't line be a string?
When I try to use words on line, it tells me
"Couldn't match expected type "IO a0" with actual type [String]
As if line isn't a string.
Furthermore, can I use :t line in the program itself when I make it to see if it's actual of the right type or not?
I apologize for the novice question, but I'm a bit stuck.
EDIT:
I did something similar in GHCI, and it tells me that my type is in fact a normal string.. I don't get it.
Prelude> line <- getLine
"Hello fellows"
Prelude> :t line
line :: String
Prelude> words line
["Hello","fellows"]
Why doesn't that work?

In haskell if you want to return a value, you have to say so:
main = do
putStrLn "Insert a string to convert: "
-- Input string
line <- getLine
return (words line)
words line isn't an IO action, it's a list of strings, so it can't be a statement in a do block.
return :: Monad m => a -> m a and in this case we can specialise it to the type a -> IO a and then to [String] -> IO [String]. Each of the statements in your do block must be IO statements.
Taking it further:
If you want to compile your program, you should have main :: IO(), which means you shouldn't return your list.
If, for example, you wanted to process those strings into a single string then output that, you could do
process :: [String] -> String
process xss = "I don't know, some answer"
main = do
putStrLn "Insert a string to convert: "
-- Input string
line <- getLine
putStrLn (process (words line))
although I'd personally write that last line as putStrLn $ process.words $ line.
Your interaction in GHCi
Prelude> line <- getLine
"Hello fellows"
Prelude> :t line
line :: String
Prelude> words line
["Hello","fellows"]
is using the fact that GHCi isn't actually just running in the IO monad. In GHCi, if your input is a valid line in a do block, it'll get run, but if it's pure code it'll get evaluated and printed. (An interactive interpreter like this is often called a REPL for Read-Eval-Print-Loop.)

Well, the question is what do you want to do with words line?
Having words line as a line inside a do block is doing nothing, but to get it to work you have to use return to wrap it up in the IO monad:
main = do
putStrLn "Insert a string to convert: "
-- Input string
line <- getLine
return (words line);
Anyway, perhaps you want to print it instead?
main = do
putStrLn "Insert a string to convert: "
-- Input string
line <- getLine
print (words line);

Related

Haskell IO : Printing Command Line Arguments

I have this program which just prints out the command line arguments.
echoArgs :: IO ()
echoArgs = do
line <- getArgs
print line
What I wanted to know is that why does this fail when I type:
echoArgs :: IO ()
echoArgs = do
line <- getArgs
putStrLn line
and also why doesn't it work when I change it to:
echoArgs :: IO String
echoArgs = do
line <- getArgs
let line' = read line :: String
putStrLn line'
Because
getArgs :: IO [String]
so line in do { line <- getArgs ; ... } is
line :: [String]
but putStrLn :: String -> IO () expects a String argument, not a list of Strings.
Similarly, read :: Read a => String -> a also expect a String argument, not a list of Strings argument.
See also: The Guide to Types in do-notation, In Vivid Colors.
print produces a String from whatever argument you give it.
putStrLn, on the other hand, expects a String as an argument. (Indeed, print = putStrLn . show.) Similarly, read expects a String as an argument; in effect, it deserializes when what you are trying to do is serialize the list.
getArgs has type IO [String], which means that line is not a String, but both String and Show a => [a] have a Show instance which print can use to make a String out of it.

Trouble shoot a Haskell program

Can anyone tell me what is the problem with this Haskell program
import Control.Monad
import Data.Char
main = do
contents <- getContents
putStrLn $ contents
putStr $ "shortLinesOnly version is " ++ (shortLinesOnly contents)
putStr $ "printOnlyLessChars version is " ++ (printOnlyLessChars contents)
shortLinesOnly :: String -> String
shortLinesOnly input =
let allLines = lines input
shortLines = filter (\line -> length line < 10) allLines
result = unlines shortLines
in result
--------------------the other way of doing this is -----------------
printOnlyLessChars contents = unlines $ filter (\a -> length a < 10) $ lines $ contents
The program works fine, but it fails when I try to print the contents (line 5). Why is it having problems printing the string via putStrLn
The error message I get is
* Couldn't match expected type `(String -> IO ())
-> t0 -> IO String'
with actual type `IO String'
* The function `getContents' is applied to one argument,
but its type `IO String' has none
In the expression: getContents putStrLn
Thanks,
This is the line that you need to focus on:
In the expression: getContents putStrLn
This is haskell showing you how it views your code, but your code doesn't look like that. This is almost always an indentation error. Check that you don't have an extra space or a tab where it doesn't belong.
As a suggestion when reading haskell type error messages there are three places to look, and you should scan all of them before fixating on a single one:
The type signature information -- do your types really match?
The expression information -- does the expression the compiler sees match your expectations, or do you need to add $ or parens
Is there a typo or indentation problem.
I frequently feel my brain starting to overheat as I try to read through a really messy Couldn't match expected type so before I get too upset over trying to read that part of the error message I carefully check the In the expression: part to make sure that there is an easy to fix issue with how I entered the code.

Read in multiple lines from standard input with arguments in Haskell

I'm trying to read in multiple lines from standard input in Haskell, plus one argument, then do something with the current line and write something to the standard output.
In my case I am trying to normalize lambda expressions. The program may receive 1 or more lambda expressions to normalize and then it has to write the result (normalized form or error) to the standard output. And the program may receive an argument (the max number of reductions). Here is the main function:
main :: IO ()
main = do
params <- getArgs
fullLambda <- getLine
let lambda = convertInput fullLambda
let redNum | (length params) == 1 = read (head params)
| otherwise = 100
case (parsing lambda) of
Left errorExp -> putStrLn ("ERROR: " ++ lambda)
Right lambdaExp -> do
let normalizedLambdaExp = reduction lambdaExp redNum
if (isNormalForm normalizedLambdaExp) && (isClosed lambdaExp)
then putStrLn ("OK: " ++ show normalizedLambdaExp)
else putStrLn ("ERROR: " ++ lambda)
where
convertInput :: String -> String
convertInput ('\"':xs) = take ((length xs) - 2) xs
convertInput input = input
So this code handles one line and completes the reductions and then writes something to the standard output. How can I change this to handle multiple lines? I've read about replicateM but I can't seem to grasp it. My mind is very OO so I was thinking maybe some looping somehow, but that is surely not the preferred way.
Also, this program has to be able to run like this:
echo "(\x.x) (\x.x)" | Main 25
And will produce:
OK: (\x.x)
And if there are multiple lines, it has to produce the same kind of output for each line, in new lines.
But also has to work without the argument, and has to handle multiple lines. I spent time on google and here, but I'm not sure how the argument reading will happen. I need to read in the argument once and the line(s) once or many times. Does someone know a not too lengthy solution to this problem?
I've tried it like this, too (imperatively):
main :: IO ()
main = do
params <- getArgs
mainHelper params
main
mainHelper :: [String] -> IO ()
mainHelper params = do
fullLambda <- getLine
And so on, but then it puts this to the standard output as well:
Main: <stdin>: hGetLine: end of file
Thank you in advance!
It appears you want to:
Parse a command line option which may or may not exist.
For each line of input process it with some function.
Here is an approach using lazy IO:
import System.Environment
import Control.Monad
main = do args <- getArgs
let option = case args of
[] -> ... the default value...
(a:_) -> read a
contents <- getContents
forM_ (lines contents) $ \aline -> do
process option aline
I am assuming your processing function has type process :: Int -> String -> IO (). For instance, it could look like:
process :: Int -> String -> IO ()
process option str = do
if length str < option
then putStrLn $ "OK: " ++ str
else putStrLn $ "NOT OK: line too long"
Here's how it works:
contents <- getContents reads all of standard input into the variable contents
lines contents breaks up the input into lines
forM_ ... iterates over each line, passing the line to the process function
The trick is that getContents reads standard input lazily so that you'll get some output after each line is read.
You should be aware that there are issues with lazy IO which you may run into when your program becomes more complex. However, for this simple use case lazy IO is perfectly fine and works well.

how would I get this function to be accepted with putStr in haskell?

how would I get this function to be accepted with putStr in haskell? so it displays each word in a list on a new line??
unlines1 :: [String] -> String
unlines1 [] = []
unlines1 (l:ls) = l ++ (putStr('\n')) : unlines ls
Let me try to be more clear in the larger space provided by an answer.
When you cause GHCi to evaluate a value, e.g.,
> "foo"
GHCi will attempt to show you that value. It does this by determining whether the type of that value is an instance of Show. If it is, GHCi prints the display string that show provides for that value. In the case of strings, show will escape non-printable characters like '\n'. This means that what GHCi actually does is more like:
> putStrLn (show "foo")
This means that
> "foo\nbar"
becomes
> putStrLn (show "foo\nbar")
which, by the definition of show for Strings, becomes
> putStrLn "foo\\nbar"
with the '\n' escaped. This is what GHCi is designed to do. You can't and shouldn't prevent it from doing so.
If, on the other hand, you want to print a String, as in perform the Haskell equivalent of echo or puts or printf, then you must use an IO action to do so. One IO action you can use is putStr :: String -> IO ().
When you evaluate
> putStr "foo"
GHCi will attempt to evaluate the IO () action and display a result. Because it is an IO action, GHCi is designed to execute (perform) the IO for you, in this case printing a string.
So the difference between
> "foo\nbar"
and
> putStr "foo\nbar"
is not that the newline is escaped in one string and unescaped in the other. The newline is always a literal newline. The issue is that the former is showing you the inspectable version of the string (with non-printables escaped) and the latter is actually printing the string.

Understanding I/O monad and the use of "do" notation

I am still struggling with Haskell and now I have encountered a problem with wrapping my mind around the Input/Output monad from this example:
main = do
line <- getLine
if null line
then return ()
else do
putStrLn $ reverseWords line
main
reverseWords :: String -> String
reverseWords = unwords . map reverse . words
I understand that because functional language like Haskell cannot be based on side effects of functions, some solution had to be invented. In this case it seems that everything has to be wrapped in a do block. I get simple examples, but in this case I really need someone's explanation:
Why isn't it enough to use one, single do block for I/O actions?
Why do you have to open completely new one in if/else case?
Also, when does the -- I don't know how to call it -- "scope" of the do monad ends, i.e. when can you just use standard Haskell terms/functions?
The do block concerns anything on the same indentation level as the first statement. So in your example it's really just linking two things together:
line <- getLine
and all the rest, which happens to be rather bigger:
if null line
then return ()
else do
putStrLn $ reverseWords line
main
but no matter how complicated, the do syntax doesn't look into these expressions. So all this is exactly the same as
main :: IO ()
main = do
line <- getLine
recurseMain line
with the helper function
recurseMain :: String -> IO ()
recurseMain line
| null line = return ()
| otherwise = do
putStrLn $ reverseWords line
main
Now, obviously the stuff in recurseMain can't know that the function is called within a do block from main, so you need to use another do.
do doesn't actually do anything, it's just syntactic sugar for easily combining statements. A dubious analogy is to compare do to []:
If you have multiple expressions you can combine them into lists using ::
(1 + 2) : (3 * 4) : (5 - 6) : ...
However, this is annoying, so we can instead use [] notation, which compiles to the same thing:
[1+2, 3*4, 5-6, ...]
Similarly, if you have multiple IO statments, you can combine them using >> and >>=:
(putStrLn "What's your name?") >> getLine >>= (\name -> putStrLn $ "Hi " ++ name)
However, this is annoying, so we can instead use do notation, which compiles to the same thing:
do
putStrLn "What's your name?"
name <- getLine
putStrLn $ "Hi " ++ name
Now the answer to why you need multiple do blocks is simple:
If you have multiple lists of values, you need multiple []s (even if they're nested).
If you have multiple sequences of monadic statements, you need multiple dos (even if they're nested).

Resources