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.
Related
I m still learning haskell and i found a tutorial that introduces the IO concepts using the following hangman simple programm
import System.IO
import System.Random
main = do
handle <- openFile "enable1.txt" ReadMode
contents <- hGetContents handle
gen <- getStdGen
let words = map init (lines contents)
(n, _) = randomR(0, (length words) - 1) gen :: (Int, StdGen)
word = words !! n
play word (map (\x -> '_') word) 6
build the print the string
hClose handle
play word known guesses
| word == known = do
putStrLn known
putStrLn "You win!!"
| guesses == 0 = do
putStrLn known
putStrLn ("You lose. the word was " ++ word ++ ".")
| otherwise = do
putStrLn known
putStrLn ("You have " ++ guesses ++ "guesses left.")
line <- getLine
let (newKnown, newGuesses) = handle (head line) word known guesses
play word newKnown newGuesses
--putStrLn (handle (head line) word)
handle letter word known guesses
| letter `elem` word = (zipWith (\w k -> if w == letter then w else k) word known, guesses)
| otherwise = (known, guesses - 1)
enable1.txt is a local file that have lots of words.
I run the file using runhaskill
and i get the following error:
:~/Documents/atom/haskell$ runhaskell hangman.hs
hangman.hs:22:36: error:
• No instance for (Num [Char]) arising from the literal ‘6’
• In the third argument of ‘play’, namely ‘6’
In a stmt of a 'do' block: play word (map (\ x -> '_') word) 6
In the expression:
do { handle <- openFile "enable1.txt" ReadMode;
contents <- hGetContents handle;
gen <- getStdGen;
let words = map init (lines contents)
(n, _) = ...
....;
.... }
hangman.hs:30:16: error:
• No instance for (Num [Char]) arising from the literal ‘0’
• In the second argument of ‘(==)’, namely ‘0’
In the expression: guesses == 0
In a stmt of a pattern guard for
an equation for ‘play’:
guesses == 0
hangman.hs:37:36: error:
• No instance for (Num [Char]) arising from a use of ‘handle’
• In the expression: handle (head line) word known guesses
In a pattern binding:
(newKnown, newGuesses) = handle (head line) word known guesses
In the expression:
do { putStrLn known;
putStrLn ("You have " ++ guesses ++ "guesses left.");
line <- getLine;
let (newKnown, newGuesses) = handle (head line) word known guesses;
.... }
Can anyone please help me understand the issue/ how to fix it.
runhaskell --version is runghc 8.0.2
Others already pointed out some issues in your code. Here, I only wanted to provide you a general suggestion.
Most Haskellers, including "experts", always start writing any new top-level function (or binding, in general) from a type annotation. That is, by writing foo :: Type1 -> Type2 -> ... -> ReturnType. Indeed, this is strongly recommended for several reasons.
First, it helps the programmer focus their mind on what kind of data they have to process or produce. This might be obvious in the programmer's mind for simple programs, but it becomes less trivial in more serious, high-level code.
Second, it prevents the type inference engine to infer unintended types. Consider this code, for instance.
foo x = "hello" ++ x -- line A
This is accepted without problems, and x is inferred to be of type String by GHC.
However, in the programmer's mind x should have been an integer, and so, later on, the programmer writes
let s = foo 42 in ... -- line B
and GHC complains that 42 is not a String. Or even worse, that Num String can not be satisfied, meaning that a string in not a numeric type. Now the programmer is puzzled because GHC point to line B as the problem, but that code looks fine to the programmer. "I'm passing an integer, foo expects an integer, where is this weird string error coming from?!?"
This is not the compiler's fault -- it has no way of knowing that the code in line A was wrong. However, if the programmer told the compiler, around line A, that x was intended to be an integer, then it would indeed have been the compiler fault! The compiler should now complain about the error in line A! And indeed, it does: here's a GHCi quick test.
> foo :: Int -> String ; foo x = "hello" ++ x
error:
• Couldn't match expected type ‘[Char]’ with actual type ‘Int’
• In the second argument of ‘(++)’, namely ‘x’
In the expression: "hello" ++ x
In an equation for ‘foo’: foo x = "hello" ++ x
Ah-ha! ++ wants a string, but x is an integer. So we have to convert it
> foo :: Int -> String ; foo x = "hello" ++ show x
Now, no error arises.
In general, when coding and making some mistake, GHC might be led to infer unintended types, leading to puzzling errors later on, pointing to seeming perfect code. In such cases, a common technique is to add more and more type annotations, informing the compiler about the programmer's intent, so that GHC can produce more meaningful errors. Eventually, GHC and the programmer agree that something is wrong, and the bug can be fixed.
You are getting errors because the types are inconsistent in the program.
No instance for (Num X) means that "X is not any kind of number".
[Char] is the type of a string (String is an alias for it).
So your error means that something is being used as a string and as a number.
Looking over your code I can see that in play you have
"You have " ++ guesses ++ "guesses left." which means that guesses must be a string, in order to be concatenated with other strings.
guesses == 0 which means that guesses must be a number.
If you got this code from the tutorial, then it is a badly written tutorial and you should find a better one. If you wrote it yourself according to the tutorial, then you must have missed a step.
In order to convert a number to a string for printing, you can use the show function:
"You have " ++ show guesses ++ "guesses left."
You cannot (++) a String and a numeral type. You should first use function show to convert the number to a String before you can connect it with another string.
In your code, parameter word and known is of some type Num a => a, but (++) accepts only two String (i.e. [Char]) as a parameter (to be precise, it accept two lists of the same type of elements, and since you have already applied a String to it, the other parameter should also be a String). So you should replace word with show word, and the same for known.
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.
I am trying to have Haskell pick a random line from a file and print it. My attempt is below:
import Data.Random.Extras (choice)
main :: IO ()
main = do
filecontents <- readFile "wordlist.txt"
let words = lines filecontents
let word = choice $ words
word >>= putStrLn
The last line is where the error occurs. >>= expects an IO String, but word is a Data.RVar.RVar String. (The variable is called `word' because each line should be one word.)
I have read the docs for RVar but after some hacking, I do not see how to solve my problem. Any ideas?
I am using ghc 7.6.3 from an installation of the Haskell Platform, OS X 10.9.
The complete error is below:
[ 01:46 PM (51) integral:thoth ~/Source/pwgen ] > ghc -o pwgen pwgen.hs
[1 of 1] Compiling Main ( pwgen.hs, pwgen.o )
pwgen.hs:40:3:
Couldn't match type `Data.RVar.RVarT
Data.Functor.Identity.Identity'
with `IO'
Expected type: IO String
Actual type: Data.RVar.RVar String
In the first argument of `(>>=)', namely `word'
In a stmt of a 'do' block: word >>= putStrLn
In the expression:
do { filecontents <- readFile "wordlist.txt";
let words = lines filecontents;
let word = choice $ words;
word >>= putStrLn }
Finally, I am aware that there are more efficient ways to pick a random line from a file. I'm just going for the bare minimum that works. I am also very much a Haskell beginner and may have some fundamental misconceptions, especially regarding IO and monads.
You can use
import Data.Random
and then modify main
main = do
...
let word = sample $ choice words
putStrLn =<< word
This works because when you import Data.Random it contains an instance of MonadRandom for IO and gives you sample as a convenient wrapper for runRVar with a generator obtained from the IO monad.
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);
I was following the code in http://www.haskell.org/haskellwiki/Hitchhikers_guide_to_Haskell, and the code (in chapter 2) gives an error. There is no author name/email mentioned with the tutorial, so I am coming here for advise. The code is below, and the error occurs on the "eof" word.
module Main where
import Text.ParserCombinators.Parsec
parseInput =
do dirs <- many dirAndSize
eof
return dirs
data Dir = Dir Int String deriving Show
dirAndSize =
do size <- many1 digit
spaces
dir_name <- anyChar `manyTill` newline
return (Dir (read size) dir_name)
main = do
input <- getContents
putStrLn ("Debug: got inputs: " ++ input)
That tutorial was written a long time ago, when parsec was simple. Nowadays, since parsec-3, the library can wrap monads, so you now have to specify (or otherwise disambiguate) the type to use at some points. This is one of them, giving eof e.g. the expression type signature eof :: Parser () makes it compile.