I have a simple function like:
nth :: Integer -> Integer
And I try to print it's result as follows:
main = do
n <- getLine
result <- nth (read n :: Integer)
print result
The following error is generated:
Couldn't match expected type `IO t0' with actual type `Integer'
In the return type of a call of `nth'
In a stmt of a 'do' expression:
result <- nth (read n :: Integer)
Also tried with putStrLn and a lot of other combinations with no luck.
I can't figure it out and I would need some help, being that I don't fully understand how stuff works around these IOs.
nth is a function, not an IO action:
main = do
n <- getLine
let result = nth (read n :: Integer)
print result
The do syntax unwraps something within a monad. Everything on the right hand side of the arrow must live within the IO monad, otherwise the types don't check. An IO Integer would be fine in your program. do is syntactic sugar for the more explicit function which would be written as follows:
Recall that (>>=) :: m a -> (a -> m b) -> m b
main = getLine >>= (\x ->
nth >>= (\y ->
print y))
But nth is not a monadic value, so it doesn't make sense to apply the function (>>=), which requires something with the type IO a.
Related
Sorry if I am being silly but I am a beginner in Haskell ans I am trying to make a print a List with putStrLn but i am not sure how to solve the next problem:
And I am trying to made a basic print List in Haskell with the code:
import System.IO
array = map show [1, 2, 3, 4]
main :: IO ()
main = do
map putStrLn array
but the compiler give me:
8 main.hs:7:3: error:
7 • Couldn't match expected type ‘IO ()’ with actual type ‘[IO ()]’
6 • In a stmt of a 'do' block: map putStrLn array
5 In the expression: do map putStrLn array
4 In an equation for ‘main’: main = do map putStrLn array
How I should fix it?
Haskell handles IO quite differently than other languages.
In a language like Java, System.Out.println(3) is a statement which does not evaluate to a value, so you can't even write something like x = System.Out.println(3);.
In a language like Lisp, (print 3) evaluates to 3 and, in the process of evaluation, prints 3. So saying something like (setq x (print 3)) will set the value of x to 3 and also print 3.
In Haskell, putStrLn "3" represents the command to print 3. Thus, saying x = putStrLn "3" does absolutely nothing except assign x to the command putStrLn "3".
Let's look at some types. We have
map :: (a -> b) -> [a] -> [b]
putStrLn :: String -> IO ()
Thus, we should have
map putStrLn :: [String] -> [IO ()]
map putStrLn array :: [IO ()]
In other words, map putStrLn array is a list of "IO actions" which result in a value of type () (basically, this means that executing the actions results in no extra information).
However, in order to write
main :: IO ()
main = map putStrLn array
which is what
main :: IO ()
main = do map putStrLn array
translates to, we need map putStrLn to be of type IO (), NOT of type [IO ()].
If you wish to execute an action for each element of a list, you can use the for_ function, which has type for_ :: (Foldable g, Applicative f) => g a -> (a -> f ()) -> f (). IO is Applicative and [] is Foldable, so in particular for_ :: [String] -> (String -> IO ()) -> IO () is one type that for_ can take. The code looks like
import Data.Foldable (for_)
array :: [String]
array = map show [1, 2, 3, 4]
main :: IO ()
main = for_ array putStrLn
This would be equivalent in an imperative language to
for each x in array do {
putStrLn x;
}
I want to ask the user for a sentence, and then return the sentence back but with the words on separate lines.
For example, if the user inputs "hello I am tall", the computer returns:
hello,
I
am
tall
I tried to start off a bit, but don't know of a function or something I can use to try and separate the sentence. My code so far:
displayWords ::IO ()
displayWords = do putStr "Please enter a line of text"
x <- getLine
mapM print x
I get the error:
Couldn't match type ‘[()]’ with ‘()’
EDIT: One more side thing... using mapM_ print (words x) fixes what I want, but is there a way to print this without the quotation marks?
EDIT2: One more thing... Someone in the comments helped answer the previous edit, but if I change the format of this to
displayWords:: String -> IO Int()
displayWords s = do
mapM_ putStrLn s
return (length s)
I get the error
Couldn't match type 'Char' With '[Char]'
How come putStrLn doesn't work here?
You need the words function to split the string into separate words.
Someone suggested mapM_ print (words x), but since each word is a string, using print will wrap it in quote marks, which you don't want. So try
mapM_ putStrLn (words x)
Use mapM_.
mapM print returns a list, the result of calling print for each element, but since print returns just () that is [()] not very meaningful.
-- here, b = ()
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM_ print discards the result of each call:
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
displayWords must be of type IO (), and the type of a do-block is the type of its last statement, this is why mapM results in a type error.
Another way would be to ignore the result of a function like mapM by adding a statement that does nothing.
do putStr "..."
x <- getLine
mapM print x
return ()
I'm trying to write code that will prompt the user to enter a Float and will continue to do so until a valid float is entered.
I've tried the following approach:
getFloat :: Float
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> f
Nothing -> do getFloat
But I'm getting the following error:
Main.hs:41:5:
Couldn't match type `IO b0' with `Float'
Expected type: IO String -> (String -> IO b0) -> Float
Actual type: IO String -> (String -> IO b0) -> IO b0
In a stmt of a 'do' block: input <- getLine
In the expression:
do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> do { ... } } }
In an equation for `getFloat':
getFloat
= do { input <- getLine;
case (readMaybe input :: Maybe Float) of {
Just f -> f
Nothing -> ... } }
Main.hs:42:56:
Couldn't match expected type `IO b0' with actual type `Float'
In the expression: f
In a case alternative: Just f -> f
Main.hs:43:60:
Couldn't match expected type `IO b0' with actual type `Float'
In a stmt of a 'do' block: getFloat
In the expression: do { getFloat }
I'm a beginner a would very much appreciate if someone could explain what am I missing here.
For the Just case, use -> return f instead of -> f.
And then just remove the type signature for getFloat. After it compiles, have ghci tell you what the type signature for getFloat is.
Complete code:
getFloat = do
input <- getLine
case (readMaybe input :: Maybe Float) of Just f -> return f
Nothing -> do getFloat
Update
You might be interested in this highly-polymorphic version of the loop:
{-# LANGUAGE NoMonomorphismRestriction #-}
import Text.Read
getItem = do
input <- getLine
case readMaybe input of
Nothing -> getItem
Just x -> return x
I have purposely written getItem without a type signature - this is something that GHC can infer and fill in for you. I've also used the NoMonomorphismRestriction pragma so that getItem remains polymorphic.
The idea is that getItem can be used for any type that can be read - Floats, Doubles, Strings, etc. The type used by readMaybe can be controlled by the caller in various ways. Here are some examples:
main = do
f1 <- getItem
f2 <- getItem
let r = f1 + f2 :: Float
print r
By forcing r to be type Float, f1 and f2 must also be Floats, and therefore getItem will try to parse a Float.
Here is another way to influence the type that readMaybe uses:
main = do
f <- getItem :: IO Float
i <- getItem :: IO Int
print $ f^i -- compute f raised to the i-th power
getFloat :: Float
This states that getFloat is a constant of type Float, which is not what you want.
getFloat :: IO Float
This instead states that getFloat is an IO action producing a Float.
Once this is fixed, then you need to add return in front of your f, as #ErikR already explained. The return turns the pure float value f into an IO action which produces it, without actually performing any IO.
Finally, you do not need the do in the last do getFLoat. The do syntax is useful to sequence IO actions: if you only have one, it is redundant.
I tried to print map function's list output using putStrLn as,
main = do
let out = "hello\nworld\nbye\nworld\n"
putStrLn $ map ("out: " ++) $ lines out
It throws error as,
Couldn't match type ‘[Char]’ with ‘Char’
I referred some other code and changed the lastline to
mapM_ putStrLn $ map ("out: " ++) $ lines out
It solves the problem, but how does map monad with underscore suffix work in this case?
mapM_ is based on the mapM function, which has the type
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
And mapM_ has the type
mapM_ :: Monad m => (a -> m b) -> [a] -> m ()
With the former, it acts like the normal map over a list, but where each element has an action run with the results aggregated. So for example if you wanted to read multiple files you could use contents <- mapM readFile [filename1, filename2, filename3], and contents would be a list where each element represented the contents of the corresponding file. The mapM_ function does the same thing, but throws away the results. One definition is
mapM_ f list = do
mapM f list
return ()
Every action gets executed, but nothing is returned. This is useful in situations like yours where the result value is useless, namely that () is the only value of type () and therefore no actual decisions can be made from it. If you had mapM putStrLn someListOfStrings then the result of this would have type IO [()], but with mapM_ putStrLn someListOfStrings the [()] is thrown away and just replaced with ().
checkstring :: [String] -> Int -> [String]
checkstring p n = do z <- doesFileExist (p !! n)
if z
then p
else error $ "'" ++ (p !! n) ++ "' file path does not exist"
It checks for a element in the string by looking at "n"(so if n = 2 it will check if the second string in the list) then see if it exists. If it does exist it will return the original string list, if not it will error.Why does it do this? :
Couldn't match expected type `[t0]' with actual type `IO Bool'
In the return type of a call of `doesFileExist'
In a stmt of a 'do' expression: z <- doesFileExist (p !! n)
The type of doesFileExist is String -> IO Bool. If your program wants to know whether a file exists, it has to interact with the file system, which is an IO action. If you want your checkString function to do that, it will also have to have some kind of IO-based type. For example, I think something like this would work, though I haven't tried it:
checkstring :: [String] -> Int -> IO [String]
checkstring p n = do z <- doesFileExist (p !! n)
if z
then return p
else error $ "'" ++ (p !! n) ++ "' file path does not exist"
To add to what MatrixFrog has mentioned in his answer. If you look at your function signature i.e [String] -> Int -> [String] it indicates that this function is a pure function and doesn't involved any side effects, where as in your function body you are using doesFileExist which has a signature of String -> IO Bool where the presence of IO indicates it is a impure function i.e it involves some IO. In haskell there is a strict separation between impure and pure functions and as a matter of fact if your function calls some other function which is impure than your function is also impure. So in your case your function checkString needs to be impure and that can be done by making it return IO [String], which is what MatrixFrog has mentioned in his answer.
On another note, I would suggest that you can make the function to be something like:
checkString :: String -> IO (Maybe String) ,as your function doesn't need the whole list of string as it just need a specific string from the list to do its work and rather than throwing an error you can use Maybe to detect the error.
This is just a suggestion but it also depends on how your function is being used.
I think the problem is that your type signature forces the do block to assume that it is some other monad. For example, suppose you're working in the list monad. Then, you could write
myFcn :: [String] -> Int -> [String]
myFcn p n = do
return (p !! n)
In the case of the list monad, the return simply returns the singleton list, so you get behavior like,
> myFcn ["a", "bc", "d"] 1
["bc"]
(My personal opinion is that it would be very helpful if the GHC had an option to print out common mistakes that could cause a type error; I sympathize with the asker in that I've gotten a lot of type error messages that take time to figure out).