How can I use map with a string got from getLine?[Haskell] - haskell

I want to read a String and toUpper all the characters.
import Data.Char
main = do
a <- getLine
b <- getLine
map toUpper a
if (a == b)
then print 0
else if (a < b)
then print (-1)
else print 1
Then I got this
Couldn't match expected type `IO a0' with actual type `[b0]'
In the return type of a call of `map'
In a stmt of a 'do' expression: map toUpper a
In the expression:
do { a <- getLine;
b <- getLine;
map toUpper a;
if (a == b) then
print 0
else
if (a < b) then print (- 1) else print 1 }
Hou can I use map with a String got from getLine?
Or there is another way to read a String and toUpper all the characters ?

You are not assigning the "result" of your map call to anything at all. This is causing the type error you are getting, which is telling you that you are trying to return a string (the result of the map call), when it really needs to be some IO type.
A direct fix would look something like this:
import Data.Char
main = do
a <- getLine
b <- getLine
let c = map toUpper a
if (c == b)
then print 0
else if (c < b)
then print (-1)
else print 1
If you use fmap you can toUpper all the chars and get the line of input at the same time (preventing the need for a c).
import Data.Char
main = do
a <- fmap (map toUpper) getLine
b <- getLine
if a == b
then print 0
else if a < b
then print (-1)
else print 1

Others have corrected your program in the minimal way, but I want to point out a C-ism that Haskell has improved:
if (a == b)
then print 0
else if (a < b)
then print (-1)
else print 1
Has it ever bothered you that numbers were appropriated for recording how a thing compared? It's certainly bothered me. Fortunately, defining new data types in Haskell is so cheap that we do it all the time. In the standard library, there's a type defined as follows:
data Ordering = LT | EQ | GT
And there's a standard function
compare :: Ord a => a -> a -> Ordering
So why not use this beautiful Haskell artifact?
main = do
a <- getLine
b <- getLine
print (compare (map toUpper a) b)

in Haskell it's a good practice to separate non-monadic code from monadic one.
A very minimal improvement is to move print outwards:
print $ if (a == c)
then 0
else if (a < b)
then (-1)
else 1
As for an idiomatic solution, think of separating all non-monadic code in a separate function (both comparison and uppercasing).
Also, if you see elsif in your code, think about guards:
c_compare a c
| a == c = 0
| a < c = -1
| otherwise = 1
A case implementation is also possible:
c_compare a c = case (compare a c) of
LT -> -1
EQ -> 0
GT -> 1

Remember, everything in Haskell is immutable, so calling map toUpper a doesn't actually modify a. If you'd like to save that result, you'll have to bind it to a variable in a let clause. So you might want to change your code to something like this:
import Data.Char
main = do
a <- getLine
b <- getLine
let c = map toUpper a
if (a == c)
then print 0
else if (a < b)
then print (-1)
else print 1

Related

Haskell how can I show function result

I have a question that asks me find 'quadratic equation' and show result and add number of the roots
example:
Main> quadratric 2 2 2
2x^2 + 2x + 2 = 0
Has no real roots.
Main> quadratic 2 5 2
2x^2 + 5x + 2 = 0
Has two real roots:
-2.0 and -0.5
So this is quadratic equation:
quadraticprob a b c
| root < 0 = error "Has no real roots"
| root == 0 = [-b/(2*a)]
| root > 0 = [-b/(2*a) + sqroot/(2*a),
-b/(2*a) - sqroot/(2*a)]
where
root = b*b - 4*a*c
sqroot = sqrt root
I can get the result but I should add how many roots they have so I should use one more function that getLine and show the result.
I made this but it's totally wrong:
readresult :: IO ()
readresult = do
line <- getLine
putStrLn (show (quadraticprob (read line))
Can you help me with my mistake please?
Assume you want get 3 integers from standard input call "getLine" function once.
The expression
line <- getLine
will return a string like (for example)
"2 2 2"
with spaces between each integer. The first thing need to do is to remove the space and convert it from string to Int type. the words and read functions can solve this easily as below:
map read (words line)::[Int]
However, a integers list cannot pass to your quadratic function directly, it need use case get elements from list as below
case map read (words line)::[Int] of
[a, b, c] -> putStrLn $ show $ quadraticprob a b c
If you want read real number instead of integers, just change map..::[Int] to ::[Double].
A few hints:
Use a getLine for each argument
... = do
astr <- getLine
bstr <- getLine
cstr <- getLine
putStrLn (show (quadraticprob (read astr) (read bstr) (read cstr)))
For quadraticprob, it's not clear what your goal actually is. Before writing any code, you should start by writing the intended type.
quadraticprob :: ?? -> ?? -> ?? -> ??
What should that be?

How can I get the value of a Monad without System.IO.Unsafe? [duplicate]

This question already has answers here:
How to get normal value from IO action in Haskell
(2 answers)
Closed 7 years ago.
I just started learning Haskell and got my first project working today. Its a small program that uses Network.HTTP.Conduit and Graphics.Rendering.Chart (haskell-chart) to plot the amount of google search results for a specific question with a changing number in it.
My problem is that simple-http from the conduit package returns a monad (I hope I understood the concept of monads right...), but I only want to use the ByteString inside of it, that contains the html-code of the website. So until now i use download = unsafePerformIO $ simpleHttp url to use it later without caring about the monad - I guess that's not the best way to do that.
So: Is there any better solution so that I don't have to carry the monad with me the whole evaluation? Or would it be better to leave it the way the result is returned (with the monad)?
Here's the full program - the mentioned line is in getResultCounter. If things are coded not-so-well and could be done way better, please remark that too:
import System.IO.Unsafe
import Network.HTTP.Conduit (simpleHttp)
import qualified Data.ByteString.Lazy.Char8 as L
import Graphics.Rendering.Chart.Easy
import Graphics.Rendering.Chart.Backend.Cairo
numchars :: [Char]
numchars = "1234567890"
isNum :: Char -> Bool
isNum = (\x -> x `elem` numchars)
main = do
putStrLn "Please input your Search (The first 'X' is going to be replaced): "
search <- getLine
putStrLn "X ranges from: "
from <- getLine
putStrLn "To: "
to <- getLine
putStrLn "In steps of (Only whole numbers are accepted):"
step <- getLine
putStrLn "Please have some patience..."
let range = [read from,(read from + read step)..read to] :: [Int]
let searches = map (replaceX search) range
let res = map getResultCounter searches
plotList search ([(zip range res)] :: [[(Int,Integer)]])
putStrLn "Done."
-- Creates a plot from the given data
plotList name dat = toFile def (name++".png") $ do
layout_title .= name
plot (line "Results" dat)
-- Calls the Google-site and returns the number of results
getResultCounter :: String -> Integer
getResultCounter search = read $ filter isNum $ L.unpack parse :: Integer
where url = "http://www.google.de/search?q=" ++ search
download = unsafePerformIO $ simpleHttp url -- Not good
parse = takeByteStringUntil "<"
$ dropByteStringUntil "id=\"resultStats\">" download
-- Drops a ByteString until the desired String is found
dropByteStringUntil :: String -> L.ByteString -> L.ByteString
dropByteStringUntil str cont = helper str cont 0
where helper s bs n | (bs == L.empty) = L.empty
| (n >= length s) = bs
| ((s !! n) == L.head bs) = helper s (L.tail bs) (n+1)
| ((s !! n) /= L.head bs) = helper s (L.tail bs) 0
-- Takes a ByteString until the desired String is found
takeByteStringUntil :: String -> L.ByteString -> L.ByteString
takeByteStringUntil str cont = helper str cont 0
where helper s bs n | bs == L.empty = bs
| n >= length s = L.empty
| s !! n == L.head bs = L.head bs `L.cons`
helper s (L.tail bs) (n + 1)
| s !! n /= L.head bs = L.head bs `L.cons`
helper s (L.tail bs) 0
-- Replaces the first 'X' in a string with the show value of the given value
replaceX :: (Show a) => String -> a -> String
replaceX str x | str == "" = ""
| head str == 'X' = show x ++ tail str
| otherwise = head str : replaceX (tail str) x
This is a lie:
getResultCounter :: String -> Integer
The type signature above is promising that the resulting integer only depends on the input string, when this is not the case: Google can add/remove results from one call to the other, affecting the output.
Making the type more honest, we get
getResultCounter :: String -> IO Integer
This honestly admits it's going to interact with the external world. The code then is easily adapted to:
getResultCounter search = do
let url = "http://www.google.de/search?q=" ++ search
download <- simpleHttp url -- perform IO here
let parse = takeByteStringUntil "<"
$ dropByteStringUntil "id=\"resultStats\">" download
return (read $ filter isNum $ L.unpack parse :: Integer)
Above, I tried to preserve the original structure of the code.
Now, in main we can no longer do
let res = map getResultCounter searches
but we can do
res <- mapM getResultCounter searches
after importing Control.Monad.

How to get output of function returning Maybe?

This is a newbie question.
I am having a trouble understanding the output of StripPrefix function which returns Maybe [a].
What I am doing is, I am passing two strings to StripPrefix so that it gives back the string after cutting the prefix.
What I have tried is :
let b = stripPrefix pref stri
Just b <- stripPrefix pref stri
In first case, my print operation (putStrLn b) throws error "Couldn't match type Maybe [Char]' with[Char]'"
From the comments on the question:
In GHCi, if you want to extract the a from a Maybe a you have a few options. First, if you're sure it will succeed with a Just something, you can do
> let Just a = Just 1
> print a
1
However, this can lead to problems if your operation is not successful
> let Just a = Nothing :: Maybe Int
> print a
*** Exception <interactive>12:5-20: Irrefutable pattern failed for pattern Data.Maybe.Just a
All this is saying is that the pattern matching you used failed. How do we avoid this? There's case statements:
> -- Enable multiline input (I have this in my .ghci file so it's always on)
> :set +m
> let maybeA = Just 1
|
> case maybeA of
| Just x -> print x
| Nothing -> return () -- Do nothing
|
1
But this is laborious. Wouldn't it be nice if there was an alternative built-in to Haskell? Fortunately, there is in the Data.Maybe module:
> import Data.Maybe
> :type maybe
maybe :: b -> (a -> b) -> Maybe a -> b
> -- The -1 is our default value in case of Nothing
> print $ maybe (-1) id $ Just 1
1
> print $ maybe (-1) id $ Nothing
-1
There's even an easier function to use when all you want is either the value in a Just or a default value:
> print $ fromMaybe (-1) $ Just 1
1
But maybe is more powerful in general:
> print $ maybe 0 (\x -> 2 * x - x * x * x + 7 ^ x) $ Just 3
322
There are still times, though, that all you want to know is if an operation was successful. For that, Data.Maybe has isJust and isNothing:
> isJust $ Just 1
True
> isJust $ Nothing
False
And isNothing = not . isJust, obviously.
That's because putStrLn :: String -> IO () and b :: Maybe String. putStrLn expects its first argument to be a String, and that's not what b is. You can use print :: Show a => a -> IO () to print a Maybe value, provided that the type it contains is itself Showable.

Does Maybe MonadPlus Parsers need to be in certain order?

Im working through the exercises on wikibooks/haskell and there is an exercise in the MonadPlus-chapter that wants you to write this hexChar function. My function works as shown below, but the thing is that when I try to switch the 2 helper parsers (digitParse and alphaParse) around the function ceases to work properly. If I switch them around I can only parse digits and not alphabetic chars anymore.
Why is this so?
char :: Char -> String -> Maybe (Char, String)
char c s = do
let (c':s') = s
if c == c' then Just (c, s') else Nothing
digit :: Int -> String -> Maybe Int
digit i s | i > 9 || i < 0 = Nothing
| otherwise = do
let (c:_) = s
if read [c] == i then Just i else Nothing
hexChar :: String -> Maybe (Char, String)
hexChar s = alphaParse s `mplus` digitParse s -- cannot switch these to parsers around!!
where alphaParse s = msum $ map ($ s) (map char (['a'..'f'] ++ ['A'..'F']))
digitParse s = do let (c':s') = s
x <- msum $ map ($ s) (map digit [0..9])
return (intToDigit x, s')
if read [c] == i then Just i else Nothing
The marked code has a flaw. You're using Int's Read instance, e.g. read :: String -> Int. But if it's not possible to parse [c] as an int (e.g. "a"), read will throw an exception:
> digit 1 "doesnt start with a digit"
*** Exception: Prelude.read: no parse
> -- other example
> (read :: String -> Int) "a"
*** Exception: Prelude.read: no parse
Instead, go the other way:
if [c] == show i then Just i else Nothing
This will always works, since show won't fail (not counting cases where bottom is involved).

Pretty printing a syntax tree in Haskell

I don't understand this type error:
Couldn't match expected type `[t0]' with actual type `IO ()'
In the return type of a call of `printv'
In a stmt of a 'do' expression: px <- printv x
In the expression:
do { px <- printv x;
sep <- print ", ";
rest <- prints xs;
return (px : sep : rest) }
From:
data Value = IntValue Int
| TruthValue Bool
deriving (Eq, Show)
printv :: Value -> IO()
printv (IntValue i) = print i
printv (TruthValue b) = print ("boolean" ++ show b)
prints :: [Value] -> [IO()]
prints [] = []
prints (x:xs) = do px <- printv x
sep <- print ", "
rest <- prints xs
return (px:sep:rest)
It looks to me like every element (px) is converted into an IO() action, and then that is added to a list of the same things, thus producing an [IO()] list.
What am I missing here? Converting it to a list of strings, by removing the print's, works fine.
You're missing the return on the [] case of prints:
prints [] = return []
However, your prints is very strange. It returns a [()], because print is outputting strings to the console, not returning them.
Do you mean to return strings from your printv function?
Since you're trying to pretty print a syntax tree, here's roughly the right way to do it:
Use pretty-printing combinators
Use a pretty typeclass
Like so:
import Text.PrettyPrint
import Data.List
data Value
= VInt Int
| VBool Bool
deriving (Eq, Show)
class Pretty a where
pretty :: a -> Doc
instance Pretty Value where
pretty (VInt i) = int i
pretty (VBool b) = text "Boolean" <+> text (show b)
draw :: [Value] -> String
draw = intercalate ", " . map (render.pretty)
main = putStrLn $ draw [VInt 7, VBool True, VInt 42]
Running it:
*A> main
7, Boolean True, 42
Take a closer look at the type of your function:
prints :: [Value] -> [IO()]
But if we now take a look at prints [] = [], this can't match, because the type of that one is
prints :: [t] -> [a]
Therefore, you missed using prints [] = return [], to make it work.
If you're not evaluating an IO action, you don't need a do block. Just treat IO () as a normal type.
prints (x:xs) = printv x : print ", " : prints xs
You don't want prints to return an array of IO actions. You want it to return a single IO action that represents each of the IO actions bound together. Something like:
prints xs = mapM_ (\x -> printv x >> putStr ", ") xs
Except that I don't think the new lines are going to end up where you want them.
Look at the documentation for mapM and sequence for more information. In particular, the implementation of sequence is probably similar to what you're trying to do.
However, I would really recommend that instead doing all the work in an IO function, you should write a pure function to render the textual format you want, and then just print that. In particular, it seems that an instance of Show for Value would be appropriate.
instance Show Value where
show (IntValue i) = show i
show (TruthValue b) = "boolean " ++ show b
That way you can just call print value rather than printv value, and if you really wanted to you could define prints as follows.
import Data.List
prints :: (Show a) => [a] -> IO ()
prints = putStrLn . intercalate ", " . map show`.

Resources