I have this which works fine:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= putStrLn . show >> return ()
myFunc1 :: Int -> Int -> IO Bool
myFunc1 .....
I want to do add an additional string to the output:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= (++) "the result is: " >>= putStrLn . show >> return ()
But that doesn't compile. I've tried different variations but still no success. Your suggestions?
The first thing that sticks out is that the expression:
(++) "the result is: "
is not an IO-action - it's just a pure function String -> String, and
that's one reason why you code isn't type checking.
To turn it into an IO-action you can compose it with return:
return . ( (++) "the result is: " )
:: String -> IO String
Now you can use it with >>=.
However, that's not where the real problem is...
To prepend "the result is: " before the show you have to insert it in the putStrLn call:
... >>= putStrLn . (++ "the result is: ") . show
(Note that there is no need to >> return () since putStrLn already returns ()).
Honestly, this is a lot simpler using do-notation:
forM_ [1..10] $ \x -> do
s <- myFunc1 x 99
putStrLn $ "the result is: " ++ show s
You can compose show with the concatenation function like so:
forM_ [1..10] $ \x -> myFunc1 x 99 >>= putStrLn . ("the result is: " ++) . show >> return ()
Replace ++ with add
add x y = return (x ++ show (y))
forM_ [1..10] $ \x -> myFunc1 x 99 >>= add "the result is: " >>= putStrLn . show >> return ()
reason: The return type of ++ is not IO type
Related
I have the following (from here):
for_ [1..10] $ (\x -> T.putStrLn $ T.pack $ show x )
I'm trying to rewrite this in terms more like
applylike myfunction toList
rather than
applylike tolist myfunction
I understand the flip function can be employed to change argument order:
flip :: (a -> b -> c) -> b -> a -> c
flip f takes its (first) two arguments in the reverse order of f.
>>> flip (++) "hello" "world"
"worldhello"
This works as my original:
import Data.Foldable (for_)
:t flip
-- 1
for_ [1..10] $ (\x -> T.putStrLn $ T.pack $ show x )
-- success
But when I try to apply it directly, this fails:
-- 2
flip for_ $ (\x -> T.putStrLn $ T.pack $ show x ) [1..10]
-- fail
I notice, however, that if I remove the $ operator which was required in (1), it succeeds:
-- 3
flip for_ (\x -> T.putStrLn $ T.pack $ show x ) [1..10]
-- success
But I don't understand why that scans correctly. When I remove the $ operator from the original non-flipped version (1), that also fails.
-- 4
for_ [1..10] (\x -> T.putStrLn $ T.pack $ show x )
-- fail
How are these being parsed that $ is required in (1) and required not to be present in (3)?
Update
Apologies: 4 above does succeed. I must have had a typo while investigating this, which certainly added to my confusion. For future readers, 4 does not fail and the universe makes more sense, and both comments and the answer accepted below were very helpful in this investigation.
Because that's how the $ operator works. This operator is not part of Haskell syntax, but a regular user-defined operator, like any other. It's defined like this:
f $ x = f x
Therefore, if you write something like:
f a $ b
That is the same as:
f a b
But if you write something like:
f $ a b
That is the same as:
f (a b)
This is because function application a b (i.e. function a applied to argument b) has the highest precedence in Haskell, nothing can bind stronger than the function application, including the $ operator.
Therefore, your first attempt:
flip for_ $ (\x -> T.putStrLn $ T.pack $ show x ) [1..10]
Is really equivalent to:
flip for_ ( (\x -> T.putStrLn $ T.pack $ show x ) [1..10] )
Which is clearly not what you meant.
In the haskell wikibook, one is asked to write something like this:
adding = do
putStrLn "enter first number"
first <- readMaybe <$> getLine
putStrLn "enter second number"
second <- readMaybe <$> getLine
let x = (+) <$> first <*> second :: Maybe Double
case x of
Just d -> putStrLn $ "the sum is " ++ show d
Nothing -> do
putStrLn "not good"
adding
This asks for two numbers and then adds them. However I tried to write it a little bit shorter, doing both getlines on the same line:
adding2 = do
putStrLn "enter two numbers"
x <- (+) <$> (readMaybe <$> getLine) <*> (readMaybe <$> getLine)
case x of
Just d -> putStrLn $ "the sum is " ++ show d
Nothing -> do
putStrLn "not good"
adding
but this doesn't work. It complains about the type of d, and I suspect it is because I haven't said anywhere that it should be a Maybe Double.
Or maybe it is the line (+) <$> (readMaybe <$> getLine) <*> (readMaybe <$> getLine)?
How can I fix this?
Apparently the problem is that I have two different monads and can't do what I'm hoping to do. I wrote one variant that I'm particularly happy with:
adding5 :: IO ()
adding5 = do
putStrLn "enter two numbers"
let a = readMaybe <$> getLine
a >>= \ a1 -> a >>= \ a2 ->
case (+) <$> a1 <*> a2 of
Just d -> putStrLn $ "the sum is " ++ show d
Nothing -> do putStrLn "not good"
adding5
Here is another one following amalloy's suggestion in the comments:
adding6 = do
putStrLn "enter two numbers"
[a1, a2] <- replicateM 2 (readMaybe <$> getLine)
case (+) <$> a1 <*> a2 of
Just d -> putStrLn $ "the sum is " ++ show d
Nothing -> do putStrLn "not good"
adding6
In the original function, you had
first :: Maybe Double
second :: Maybe Double
So when you combined them with <$> and <*> you were operating in a Maybe context: exactly what you wanted.
But in your new function, your second argument to <*> is
readMaybe <$> getLine :: Read t => IO (Maybe t)
You're now using <$> and <*> in the IO context, not the Maybe context, and so the things you are trying to add are of type Maybe t, not t. You can't add values of type Maybe t no matter what t is, because Maybe is not Num. So even if you give the compiler enough information to conclude that t should be Double, this won't work.
You have to either bind the IO values to local unwrapped names, as you did in your first function, or, equivalently, use >>= to operate inside of the IO (Maybe Double) you have.
main = do
putStrLn "Hello,Name please?"
first <- getLine
second <- getLine
third <- getLine
if (second == "divide") then putStrLn (show (read first ::Double )/ (read third :: Double))
else putStrLn "Cannot do"
So i want a number in first and third variables,and the second variable will be given the work divide and the if statement will begin and convert the String in first to a Double.But i think the issue is that the variable First is expecting a String like "one" that cannot be converted to a Double.How to fix this to allow getLine to only receive Strings that can be changed in numbers
Here's a quick idea that could help you:
import Control.Applicative
import Data.Char
getNum :: (Num a, Read a) => IO (Maybe a)
getNum = do
(x, xs) <- break (not . isDigit ) <$> getLine
case xs of
[] -> return $ Just $ read x
_ -> return Nothing
main :: IO ()
main = do
x <- getNum :: IO (Maybe Double)
case x of
Nothing -> do
putStrLn "Not a number, try again"
main
Just x' ->
putStrLn $ "Your number: " ++ show x'
return ()
You cannot "make" getLine accept only numbers, you make a function that does. You can even modify this function to accept only the first set of numbers before a non-digit (right now it returns Nothing if any non-digit is in the string).
Update
Here's a program that asks for two numbers and an operation, doing some value checking:
import Control.Applicative
import Data.Char
import Data.Maybe
getNum :: (Num a, Read a) => IO (Maybe a)
getNum = do
(x, xs) <- break (not . isDigit ) <$> getLine
case xs of
[] -> return $ Just $ read x
_ -> return Nothing
main :: IO ()
main = do
putStr "First: "
x <- getNum :: IO (Maybe Double)
putStr "Operation: "
op <- getLine
putStr "Second: "
y <- getNum :: IO (Maybe Double)
if isJust x && isJust y then do
let
x' = fromJust x
y' = fromJust y
putStr "Result: "
case op of
"divide" -> putStrLn $ show $ x' / y'
"sum" -> putStrLn $ show $ x' + y'
_ -> putStrLn "No operation"
else
putStrLn "Invalid numbers"
return ()
i have a list of tuples like:
[("3",69.46),("4",38.32),("5",111.67),("9",97.13)]
and i want to print this list of tuple like :
3 69.46
4 38.32
5 111.67
9 97.13
What is the best way to implement this?
(The length of list is dynamic)
Thanks
One way would be like this:
printList xs = mapM_ (\(a,b) -> putStr a >> putStr (" " ++ show b) >> putStrLn "") xs
Or in a more readable way:
printList xs = mapM_ (\(a,b) -> do
putStr a
putStr (" " ++ show b)
putStrLn "") xs
Or as #icktoofay points out you can use a single putStrLn:
printList xs = mapM_ (\(a,b) -> putStrLn $ a ++ " " ++ show b) xs
In ghci:
λ> printList [("3",69.46),("4",38.32),("5",111.67),("9",97.13)]
3 69.46
4 38.32
5 111.67
9 97.13
How can reverse2lines transformed into the using >>= syntax ? Just like addOneInt is transformed into addOneInt'?
addOneInt :: IO ()
addOneInt = do line <- getLine
putStrLn (show (1 + read line :: Int))
addOneInt' :: IO ()
addOneInt' = getLine >>= \line ->
putStrLn (show ( 1 + read line :: Int))
reverse2lines :: IO ()
reverse2lines =
do line1 <- getLine
line2 <- getLine
putStrLn (reverse line2)
putStrLn (reverse line1)
Please also consider reading the follow up question and its valuable answers.
You could safely deduce it from what you already know. Start by fully parenthesizing your addOneInt':
addOneInt' = getLine >>= (\line ->
putStrLn (show (1 + read line :: Int)) )
Next, you reverse2lines can be equivalently written as
reverse2lines =
do { line1 <- getLine ;
do { line2 <- getLine ;
do { putStrLn (reverse line2) ;
do { putStrLn (reverse line1) } } } }
Applying the one-step transformation that you already used for addOneInt, as much times as needed, you'd get
reverse2lines' :: IO ()
reverse2lines' =
getLine >>= (\line1 ->
getLine >>= (\line2 ->
putStrLn (reverse line2) >>
putStrLn (reverse line1) ) )
Syntactically, the parentheses around lambda expressions can be omitted, but writing them explicitly here helps to clarify and make obvious the nested structure of these functions, especially if we'd line up the indentation.
Full translation arranges for the monad's fail function to be called on pattern mismatch, but since the variable patterns (line1, line2) are irrefutable, this translation is in fact exact.
Statements of type x <- m can be translated as m >>= \x -> ..., and statements in which the return value isn't bound like m can be translated as m >> ...
reverse2lines :: IO ()
reverse2lines = getLine
>>= \line1 -> getLine
>>= \line2 -> putStrLn (reverse line2)
>> putStrLn (reverse line1)
The translation isn't exact - the fail monad function complicates things a little. You can read about it here, but as far as I know it's irrelevant when dealing with the IO monad.
Here is the code from Will's very nice answer using only >>= :
reverse2lines' :: IO ()
reverse2lines' =
getLine >>= (\line1 ->
getLine >>= (\line2 ->
putStrLn (reverse line2) >>= (\_ ->
putStrLn (reverse line1) )))
Lesson learned : the sequencing in do corresponds simply to nesting of lambda expressions.