this is my code:
askPointer = do
input <- getLine
let newInput = map toUpper input
[..here I will re-use new Input..]
return ()
Is it possible (maybe using lamba notation), to make this code shorter in one line only?
My attempt has been unsuccessfully:
input <- (\a b-> do toUpper (b <- getLine ) )
Any suggest?
Edit: little edit to make this question looking for more generic answers (not limiting to returning functions)
Applying a function to the result of an IO operation before using it is an excellent description of what fmap does.
askPointer = do
newInput <- fmap (map toUpper) getLine
[..here I will re-use new Input..]
return ()
So here fmap does exactly what you wanted - it applies map toUpper to the result of getLine before you bind that to newInput.
Try these out in your interpreter (ghci/hugs):
fmap reverse getLine
fmap tail getLine
fmap head getLine
fmap (map toUpper) getLine
If you import Data.Functor or import Control.Applicative, you can use the infix version of fmap, <$>:
reverse <$> getLine
tail <$> getLine
head <$> getLine
map toUpper <$> getLine
which means you could also write
askPointer = do
newInput <- map toUpper <$> getLine
[..here I will re-use new Input..]
return ()
fmap is a very very useful function indeed to know. You could read more in this other answer about fmap where I ended up writing a mini tutorial.
This should work:
askPointer = getLine >>= return . map toUpper
If you import Control.Applicative you can make it even shorter:
askPointer = map toUpper <$> getLine
Considering last edit:
input <- getLine >>= return . map toUpper
or
input <- map toUpper <$> getLine
Related
There is the following task:
First line is the number of cases
For each case there is a line with the number of numbers to add
For each case there is also a line with the numbers
For each case I have to print summed numbers
Example:
Input:
2
5
1 2 3 4 5
2
-100 100
Output:
15
0
This is my implementation
import Control.Monad
main = do
linesCount <- readLn :: IO Int
numbers <- replicateM linesCount getCase
mapM_ putStrLn $ map (show.sum) numbers
getCase :: IO [Int]
getCase = do
numbersCount <- readLn :: IO Int -- actually I don't need this variable
numbersString <- getLine
let numbers = map read $ words numbersString
return numbers
It looks like a lot of code for parsing input. Are there any tricks to "compress" it? :)
If you merely want to make code shorter then check out the Stack Exchange community for code golfing. That is primarily for fun and games.
If we are thinking there is too much code it may not be that we need to make it shorter but rather that we need to make it clearer. Achieving this is a matter of experience and good practice. What we want to do is isolate simple concepts which are obviously correct and then combine them in obviously correct ways. Methodologies include top-down design (break the solution into smaller pieces) and bottom-up design (from smaller pieces build up to the solution) and mixes thereof.
A bottom-up piece that hits me straight away is the task of summing a list of numbers. This has a definition in Haskell's Prelude called sum :: (Num a, Foldable t) => t a -> a. Somewhere in the final solution we are going to use this.
Another method is to simplify the problem. We can be lead astray by the way a problem is phrased. Upon closer inspection we might find an equivalent and simpler phrasing.
What information do we actually need from the input? Just the lists of numbers. What is the simplest way to obtain the lists of numbers? The number of lists seems irrelevant because there is no need to have this information before we start looking at the lists. Drop the first line and we are left with:
5
1 2 3 4 5
2
-100 100
Then, the length of each list is also irrelevant because we do not need that information before summing the list. Therefore lets also drop every other line from this point:
1 2 3 4 5
-100 100
Now we just have the lists of numbers separated by line returns where each number is separated by a space.
At this point we have a clear way to break apart the solution in a top-down manner. First we simplify the input. Secondly we parse the lists of numbers. Thirdly we sum the lists. Fourthly we print the sums. This is therefore the skeleton of our solution:
simplifyInput :: String -> [String]
parseNumberList :: String -> [Integer]
-- Note we can use `sum` from Prelude to sum the number lists.
printSums :: [Integer] -> IO ()
main :: IO ()
main = getContents >>= printSums . fmap (sum . parseNumberList) . simplifyInput
Now it is just a matter of implementing each obvious piece of the solution.
simplifyInput :: String -> [String]
simplifyInput = dropEveryOther . drop 1 . lines
where
dropEveryOther :: [a] -> [a]
In writing simplifyInput I discovered that dropping every other line requires some more work. That is okay, we can just break the solution apart again.
dropEveryOther :: [a] -> [a]
dropEveryOther [] = []
dropEveryOther (x:y:xs) = y : dropEveryOther xs
Then continuing...
parseNumberList :: String -> [Integer]
parseNumberList = fmap read . words
printSums :: [Integer] -> IO ()
printSums = putStr . unlines . fmap show
Therefore, in totality:
simplifyInput :: String -> [String]
simplifyInput = dropEveryOther . drop 1 . lines
where
dropEveryOther :: [a] -> [a]
dropEveryOther [] = []
dropEveryOther (_:y:xs) = y : dropEveryOther xs
parseNumberList :: String -> [Integer]
parseNumberList = fmap read . words
printSums :: [Integer] -> IO ()
printSums = putStr . unlines . fmap show
main :: IO ()
main = getContents >>= printSums . fmap (sum . parseNumberList) . simplifyInput
The amount of code we have has gone up (compared to the first solution) but in exchange the code is made obvious. Now you should add some documentation comments so we do not forget our explanation for the solution.
Alec posted a super compressed version of my original code in one of the comments. I decided to post a small breakdown, in case someone gets lost and has no idea what's going on in there :)
Snippets below need to be preceded with valid imports:
import Control.Monad
import Control.Applicative
So we start with Alec's version:
main = readLn >>= flip replicateM_ (getLine >> sum . map read . words <$> getLine >>= print)
He used the flip function in order to remove one set of parenthesis:
main = readLn >>= (`replicateM_` (getLine >> (print =<< sum . map read . words <$> getLine)))
He used the infix notation for replicateM_ in order to partially apply the second parameter of replicateM_, we can replace is with a lambda:
main = readLn >>= \n -> replicateM_ n (getLine >> (print =<< sum . map read . words <$> getLine))
Now let's start extracting some pieces of code into separate meaningful functions:
printBatchResult = print =<< sum . map read . words <$> getLine
main = readLn >>= \n -> replicateM_ n (getLine >> printBatchResult)
We can flip the print =<< for more readability:
printBatchResult = sum . map read . words <$> getLine >>= print
main = readLn >>= \n -> replicateM_ n (getLine >> printBatchResult)
And so on:
printBatchResult = sum . map read . words <$> getLine >>= print
handleBatch = getLine >> printBatchResult
main = readLn >>= \n -> replicateM_ n handleBatch
And again:
sumLine = sum . map read . words
printBatchResult = sumLine <$> getLine >>= print
handleBatch = getLine >> printBatchResult
main = readLn >>= \n -> replicateM_ n handleBatch
And one more time:
sumLine = sum . map read . words
handleNumbersLine = sumLine <$> getLine
printBatchResult = handleNumbersLine >>= print
handleBatch = getLine >> printBatchResult
main = readLn >>= (\n -> replicateM_ n handleBatch)
And finally the last time:
sumLine = sum . map read . words
handleNumbersLine = sumLine <$> getLine
printBatchResult = handleNumbersLine >>= print
handleBatch = getLine >> printBatchResult
handleAllBatches n = replicateM_ n handleBatch
main = readLn >>= handleAllBatches
We can replace <$> with fmap:
sumLine = sum . map read . words
handleNumbersLine = fmap sumLine getLine
printBatchResult = handleNumbersLine >>= print
handleBatch = getLine >> printBatchResult
handleAllBatches n = replicateM_ n handleBatch
main = readLn >>= handleAllBatches
We can also remove every partial application:
sumLine line = (sum . map read . words) line
handleNumbersLine = fmap sumLine getLine
printBatchResult = handleNumbersLine >>= \sum -> print sum
handleBatch = getLine >> printBatchResult
handleAllBatches n = replicateM_ n handleBatch
main = readLn >>= \numberOfBatches -> handleAllBatches numberOfBatches
And finally, add signatures:
sumLine :: String -> Int
sumLine line = (sum . map read . words) line
handleNumbersLine :: IO Int
handleNumbersLine = fmap sumLine getLine
printBatchResult :: IO ()
printBatchResult = handleNumbersLine >>= \sum -> print sum
handleBatch :: IO ()
handleBatch = getLine >> printBatchResult
handleAllBatches :: Int -> IO ()
handleAllBatches n = replicateM_ n handleBatch
main = readLn >>= \numberOfBatches -> handleAllBatches numberOfBatches
Some final comments:
>>= - the bind function from monad converts one monad to another (or the same) and transforms its value. In main function it takes IO Int, transformation lambda and returns IO () - the result of the transformation, which is empty and prints result in the process.
>> - (used in handleBatch) ignores the left parameter (how many numbers there are in a line is (arguably) unnecessary) and just returns the right parameter - which is a function handling a line with numbers.
Suppose I have a list of tuples (e.g. [(a,b)]) each a result of some previous computation.
And I want several functions to be applied on each of these elements (e.g one function might print it another send it over the network etc.)
What I've tried:
import Control.Applicative
main = do
let a = [1..5]
let fs = [(\k-> putStrLn $ show $ k*2), (\k-> putStrLn $ show $ k-2), (\k-> putStrLn $ show $ k*10)]
let res = fs <*> a
putStrLn $ "Yo"
prints just "Yo".
If you look closely res has type [IO ()] and you never use it.
So just sequence it:
main = do
let a = [1..5]
let fs = [(\k-> putStrLn $ show $ k*2), (\k-> putStrLn $ show $ k-2), (\k-> putStrLn $ show $ k*10)]
let res = fs <*> a
sequence res
putStrLn $ "Yo"
in case you want to know how you could right the complete block more concise than you could refactor the list of mappings (using sections), go with print (which is basically your putStrLn . show) and mapM_:
main = do
mapM_ print $ [(* 2), (+ (-2)), (* 10)] <*> [1..5]
putStrLn $ "Yo"
which will give
λ> :main
2
4
6
8
10
-1
0
1
2
3
10
20
30
40
50
Yo
as well ;)
note that you probably should not mix all the IO stuff with the purer computations - instead I would refactor the list of integers out:
myCombinations :: [Int] -> [Int]
myCombinations ns = [(* 2), (+ (-2)), (* 10)] <*> ns
main = do
mapM_ print $ myCombinations [1..5]
putStrLn $ "Yo"
(of course introducing functions as you go along, but I cannot guess what you are trying to achieve here)
from this you gain the ability to just check your pure functions/values:
λ> myCombinations [1..5]
[2,4,6,8,10,-1,0,1,2,3,10,20,30,40,50]
and gain probably a lot of readability ;)
If you have a list of ios :: [a -> IO b] you could use mapM ($ aValue) ios to get IO [b] or mapM_ to get IO ()
let doesn't bind anything into the monad. So IO doesn't care what you do with <*> to apply functions in a list, as long as you don't use the result in any way in a monad action.
To simply execute a list of actions in... well, sequence, you can use sequence:
let res = fs <*> a
sequence res
Imagine I read an input block via stdin that looks like this:
3
12
16
19
The first number is the number of following rows. I have to process these numbers via a function and report the results separated by a space.
So I wrote this main function:
main = do
num <- readLn
putStrLn $ intercalate " " [ show $ myFunc $ read getLine | c <- [1..num]]
Of course that function doesn't compile because of the read getLine.
But what is the correct (read: the Haskell way) way to do this properly? Is it even possible to write this function as a one-liner?
Is it even possible to write this function as a one-liner?
Well, it is, and it's kind of concise, but see for yourself:
main = interact $ unwords . map (show . myFunc . read) . drop 1 . lines
So, how does this work?
interact :: (String -> String) -> IO () takes all contents from STDIN, passes it through the given function, and prints the output.
We use unwords . map (show . myFunc . read) . drop 1 . lines :: String -> String:
lines :: String -> [String] breaks a string at line ends.
drop 1 removes the first line, as we don't actually need the number of lines.
map (show . myFunc . read) converts each String to the correct type, uses myFunc, and then converts it back to a `String.
unwords is basically the same as intercalate " ".
However, keep in mind that interact isn't very GHCi friendly.
You can build a list of monadic actions with <$> (or fmap) and execute them all with sequence.
λ intercalate " " <$> sequence [show . (2*) . read <$> getLine | _ <- [1..4]]
1
2
3
4
"2 4 6 8"
Is it even possible to write this function as a one-liner?
Sure, but there is a problem with the last line of your main function. Because you're trying to apply intercalate " " to
[ show $ myFunc $ read getLine | c <- [1..num]]
I'm guessing you expect the latter to have type [String], but it is in fact not a well-typed expression. How can that be fixed? Let's first define
getOneInt :: IO Int
getOneInt = read <$> getLine
for convenience (we'll be using it multiple times in our code). Now, what you meant is probably something like
[ show . myFunc <$> getOneInt | c <- [1..num]]
which, if the type of myFunc aligns with the rest, has type [IO String]. You can then pass that to sequence in order to get a value of type IO [String] instead. Finally, you can "pass" that (using =<<) to
putStrLn . intercalate " "
in order to get the desired one-liner:
import Control.Monad ( replicateM )
import Data.List ( intercalate )
main :: IO ()
main = do
num <- getOneInt
putStrLn . intercalate " " =<< sequence [ show . myFunc <$> getOneInt | c <- [1..num]]
where
myFunc = (* 3) -- for example
getOneInt :: IO Int
getOneInt = read <$> getLine
In GHCi:
λ> main
3
45
23
1
135 69 3
Is the code idiomatic and readable, though? Not so much, in my opinion...
[...] what is the correct (read: the Haskell way) way to do this properly?
There is no "correct" way of doing it, but the following just feels more natural and readable to me:
import Control.Monad ( replicateM )
import Data.List ( intercalate )
main :: IO ()
main = do
n <- getOneInt
ns <- replicateM n getOneInt
putStrLn $ intercalate " " $ map (show . myFunc) ns
where
myFunc = (* 3) -- replace by your own function
getOneInt :: IO Int
getOneInt = read <$> getLine
Alternatively, if you want to eschew the do notation:
main =
getOneInt >>=
flip replicateM getOneInt >>=
putStrLn . intercalate " " . map (show . myFunc)
where
myFunc = (* 3) -- replace by your own function
I am trying to make a webpage that will list the contents of a given directory, but I am running into a strange problem: The code produces the desired output when I run it line by line in GHCi, but when it is executed in the running Scotty instance, it produces different (wrong) output. Here is the relevant part of the code:
serveDir :: String -> ActionM ()
serveDir p = do let path = prefix ++ p
entries <- liftIO $ getDirectoryContents path
fs <- liftIO $ filterM (doesFileExist . ((++) prefix)) entries
ds <- liftIO $ filterM (doesDirectoryExist . ((++) prefix)) entries
liftIO $ print path >> print entries >> print fs >> print ds
blaze $ renderDir fs ds
where prefix = "static/"
(that last line in the do statement just renders it into html. this works, but the correct output never makes it to that function)
When I run each line of this function in GHCi, i get the following output:
*Main> entries <- getDirectoryContents "static/stuff"
*Main> fs <- liftIO $ filterM (doesFileExist . ((++) "static/stuff/")) entries
*Main> ds <- liftIO $ filterM (doesDirectoryExist . ((++) "static/stuff/")) entries
*Main> liftIO $ print entries >> print fs >> print ds
["..","hello","bye","someDir","."]
["hello","bye"]
["..","someDir","."]
which is what I am expecting. But when this function is run from Scotty, called as serveDir "stuff/", I get this output:
"static/stuff/"
["..","hello","bye","someDir","."]
[]
["..","."]
What is happening here? I know that ActionM is an instance of MonadIO, otherwise this would not compile. I am at a bit of a loss. Can somebody shed some light on this or advise? Rest of code available upon request, but I can say that I am using wai-middleware-static to allow static file requests, and other file request from this directory in other functions works.
fs <- liftIO $ filterM (doesFileExist . ((++) prefix)) entries
Should that not be (++) path?
Why i can't do this?
Its forbidden the use of 'do' in this question :/
How i can call words in my list and at same time result an IO?
Thanks.. this is my actual code :/
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
words y >>=
\strings ->
strings !! 1 >>=
\string->
putStr string
[Edit] Solution :
main :: IO()
main =
putStr "Name of File: " >>
getLine >>=
\st ->
openFile st ReadMode >>=
\handle ->
hGetContents handle >>=
\y ->
return (words y) >>=
\strings ->
return (strings !! 1) >>=
\string->
putStr string
Use return (words y) instead of just words y. return wraps a pure value (such as the [String] that words returns) into a monad.
From your wording, it sounds like this question is homework. If so, it should be tagged as such.
(This doesn't directly answer the question, but it will make your code more idiomatic and thus easier to read.)
You are using the pattern \x -> f x >>= ... a lot, this can (and should) be eliminated: it is (mostly) unnecessary noise which obscures the meaning of the code. I won't use your code, since it is homework but consider this example (note that I'm using return as suggested by the other answer):
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (lines str) >>=
\lns -> return (length lns) >>=
\num -> print num
(It reads a file name from the user, and then prints the number of lines in that file.)
The easiest optimisation is the section where we count the number of lines (this corresponds to the part where you are separating the words and getting the second one): the number of lines in a string str is just length (lines str) (which is the same as length . lines $ str), so there is no reason for us to have the call to length and the call to lines separate. Our code is now:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>=
\num -> print num
Now, the next optimisation is on \num -> print num. This can be written as just print. (This is called eta conversion). (You can think about this as "a function that takes an argument and calls print on it, is the same as print itself"). Now we have:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> return (length . lines $ str) >>= print
The next optimisation we can do is based on the monad laws. Using the first one, we can turn return (length . lines $ str) >>= print into print (length . lines $ str) (i.e. "creating a container that contains a value (this is done by return) and then passing that value to print is the same as just passing the value to print"). Again, we can remove the parenthesis, so we have:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>=
\str -> print . length . lines $ str
And look! We have an eta-conversion we can do: \str -> print . length . lines $ str becomes just print . length . lines. This leaves:
main = getLine >>=
\fname -> openFile fname ReadMode >>=
\handle -> hGetContents handle >>= print . length . lines
At this point, we can probably stop, since that expression is much simpler than our original one (we could keep going, by using >=> if we wanted to). Since it is so much simpler, it is also easier to debug (imagine if we had forgotten to use lines: in the original main it wouldn't be very clear, in the last one it's obvious.)
In your code, you can and should do the same: you can use things like sections (which mean \x -> x !! 1 is the same as (!! 1)), and the eta conversion and monad laws I used above.