Haskell: looping over user input gracefully - loops

This is an example from Learn You a Haskell:
main = do
putStrLn "hello, what's your name?"
name <- getLine
putStrLn ("Hey, " ++ name ++ ", you rock!")
The same redone without do for clarity:
main =
putStrLn "hello, what's your name?" >>
getLine >>= \name ->
putStrLn $ "Hey, " ++ name ++ ", you rock!"
How am I supposed to loop it cleanly (until "q"), the Haskell way (use of do discouraged)?
I borrowed this from Haskell - loop over user input
main = mapM_ process . takeWhile (/= "q") . lines =<< getLine
where process line = do
putStrLn line
for starters, but it won't loop.

You can call main again and check if your string is "q" or not.
import Control.Monad
main :: IO ()
main =
putStrLn "hello, what's your name?" >>
getLine >>= \name ->
when (name /= "q") $ (putStrLn $ "Hey, " ++ name ++ ", you rock!") >> main
λ> main
hello, what's your name?
Mukesh Tiwari
Hey, Mukesh Tiwari, you rock!
hello, what's your name?
Alexey Orlov
Hey, Alexey Orlov, you rock!
hello, what's your name?
q
λ>

May be you can also use laziness on IO type by adapting the System.IO.Lazy package. It basically includes only run :: T a -> IO a and interleave :: IO a -> T a functions to convert IO actions into lazy ones back and forth.
import qualified System.IO.Lazy as LIO
getLineUntil :: String -> IO [String]
getLineUntil s = LIO.run ((sequence . repeat $ LIO.interleave getLine) >>= return . takeWhile (/=s))
printData :: IO [String] -> IO ()
printData d = d >>= print . sum . map (read :: String -> Int)
*Main> printData $ getLineUntil "q"
1
2
3
4
5
6
7
8
9
q
45
In the above code we construct an infinite list of lazy getLines by repeat $ LIO.interleave getLine of type [T String] and by sequence we turn it into T [String] type and proceed reading up until "q" is received. The printData utility function is summing up and printing the entered integers.

Related

Why does `clockTime` not seem to work for benchmarking, in Idris?

There are probably libraries to do this (although I haven't found any), I'm actually looking to measure the time a function takes to run in Idris. The way I've found is by using clockTime from System and differentiating between before and after a function runs. Here is an example code:
module Main
import Data.String
import System
factorial : Integer -> Integer
factorial 0 = 1
factorial 1 = 1
factorial n = n * factorial (n - 1)
main : IO ()
main = do
args <- getArgs
case args of
[self ] => putStrLn "Please enter a value"
[_, ar] => do
case parseInteger ar of
Just a => do
t1 <- clockTime
let r = factorial a
t2 <- clockTime
let elapsed = (nanoseconds t2) - (nanoseconds t1)
putStrLn $ "fact(" ++ show a ++ ") = "
++ show r ++ " in "
++ (show elapsed) ++ " ns"
Nothing => putStrLn "Not a valid number"
To avoid Idris optimising the program by already evaluating the factorial, I just asked that the program be called with an argument.
This code doesn't work though: no matter what numbers I enter, such as 10000, Idris always returns 0 nanoseconds, which makes me quite sceptical, even just allocating a bigint takes time. I compile with idris main.idr -o main.
What am I doing wrong in my code? Is clockTime not a good plan for benchmarks?
Idris 1 is no longer being maintained.
In Idris 2, clockTime can be used.
clockTime : (typ : ClockType) -> IO (clockTimeReturnType typ)
An example of its use for benchmarking can be found within the Idris2 compiler, here.

I/O Loop in Haskell

I am currently working on this Haskell problem and I seem to be stuck.
Write a function, evalpoly, that will ask a user for the degree of a single variable polynomial, then read in the coefficients for the polynomial (from highest power to lowest), then for a value, and will output the value of the polynomial evaluated at that value. As an example run:
> evalpoly
What is the degree of the polynomial: 3
What is the x^3 coefficient: 1.0
What is the x^2 coefficient: - 2.0
What is the x^1 coefficient: 0
What is the x^0 coefficient: 10.0
What value do you want to evaluate at: -1.0
The value of the polynomial is 7.0
As of now, I have this:
evalpoly :: IO ()
evalpoly = putStr "What is the degree of the polynomial: " >>
getLine >>= \xs ->
putStr "What is the x^" >>
putStr (show xs) >>
putStr " coefficient: " >>
putStrLn ""
How would I go about adding the loop and calculations?
Warning:
I spoil this completely so feel free to stop at any point and try to go on yourself
Instead of pushing it all into this single function I will instead break this down into smaller tasks/functions.
So let's start with this.
1. Input
On obvious part is to ask for an value - and if we are on it we can make sure that the user input is any good (I am using Text.Read.readMaybe for this:
query :: Read a => String -> IO a
query prompt = do
putStr $ prompt ++ ": "
val <- readMaybe <$> getLine
case val of
Nothing -> do
putStrLn "Sorry that's a wrong value - please reenter"
query prompt
Just v -> return v
please note that I appended the ": " part already so you don't have to do this for your prompts
having this all the questions to your user become almost trivial:
queryDegree :: IO Int
queryDegree = query "What is the degree of the polynomial"
queryCoef :: Int -> IO (Int, Double)
queryCoef i = do
c <- query prompt
return (i,c)
where prompt = "What is the x^" ++ show i ++ " coefficient"
queryPoint :: IO Double
queryPoint = query "What value do you want to evaluate at"
please note that I provide the powers together with the coefficients - this make the calculation a bit easier but is not strictly necessary here I guess (you could argue that this is more than the function should do at this point and later use zip to get the powers too)
Asking all the inputs is now really easy once you've seen mapM and what it can do - it's the point where you usually would want to write a loop:
queryPoly :: IO [(Int, Double)]
queryPoly = do
n <- queryDegree
mapM queryCoef [n,n-1..0]
2. Evaluation
Do evaluate this I just need to evaluate each term at the given point (that is each power, coefficient pair in the list) - which you can do using map - after we just need to sum this all up (sum can do this):
evaluate :: Double -> [(Int, Double)] -> Double
evaluate x = sum . map (\ (i,c) -> c*x^i)
3. Output
Is rather boring:
presentResult :: Double -> IO ()
presentResult v = putStrLn $ "The vaule of the polynomial is " ++ show v
4. Getting it all together
I just have to ask for the inputs, evaluate the value and then present it:
evalpoly :: IO ()
evalpoly = do
p <- queryPoly
x <- queryPoint
presentResult $ evaluate x p
5. Test-Run
Here is an example run
What is the degree of the polynomial: 3
What is the x^3 coefficient: 1.0
What is the x^2 coefficient: -2.0
What is the x^1 coefficient: Hallo
Sorry that's a wrong value - please reenter
What is the x^1 coefficient: 0
What is the x^0 coefficient: 10.0
What value do you want to evaluate at: -1.0
The vaule of the polynomial is 7.0
complete Code
Note that I like to enter the no-buffering because I run into trouble on Windows occasionally if I don't have it - you probably can live without
module Main where
import Control.Monad (mapM)
import Text.Read (readMaybe)
import System.IO (BufferMode(..), stdout, hSetBuffering)
query :: Read a => String -> IO a
query prompt = do
putStr $ prompt ++ ": "
val <- readMaybe <$> getLine
case val of
Nothing -> do
putStrLn "Sorry that's a wrong value - please reenter"
query prompt
Just v -> return v
queryDegree :: IO Int
queryDegree = query "What is the degree of the polynomial"
queryCoef :: Int -> IO (Int, Double)
queryCoef i = do
c <- query prompt
return (fromIntegral i,c)
where prompt = "What is the x^" ++ show i ++ " coefficient"
queryPoint :: IO Double
queryPoint = query "What value do you want to evaluate at"
queryPoly :: IO [(Int, Double)]
queryPoly = do
n <- queryDegree
mapM queryCoef [n,n-1..0]
evaluate :: Double -> [(Int, Double)] -> Double
evaluate x = sum . map (\ (i,c) -> c*x^i)
presentResult :: Double -> IO ()
presentResult v = putStrLn $ "The vaule of the polynomial is " ++ show v
evalpoly :: IO ()
evalpoly = do
p <- queryPoly
x <- queryPoint
presentResult $ evaluate x p

`forever`: How to forward information to next iteration?

There is a thread waiting for new input in a queue to safe it to the file system. It also creates backup copies. The sscce looks like this:
import Control.Concurrent
import Control.Concurrent.STM
import Control.Monad
import Data.Time.Clock.POSIX
main :: IO ()
main = do
contentQueue <- atomically $ newTQueue
_ <- forkIO $ saveThreadFunc contentQueue
forever $ do
line <- getLine
atomically $ writeTQueue contentQueue line
saveThreadFunc :: TQueue String -> IO ()
saveThreadFunc queue = forever $ do
newLine <- atomically $ readTQueue queue
now <- round `fmap` getPOSIXTime :: IO Int
writeFile "content.txt" newLine
-- todo: Backup no more than once every 86400 seconds (24 hours).
backupContent now newLine
backupContent :: Int -> String -> IO ()
backupContent t = writeFile $ "content.backup." ++ show t
Now it would be great if the backup would not be written more than once every 24 hours. In imperative programming I would probably use a mutable int lastBackupTime inside the "forever loop" in saveThreadFunc. How can the same effect be achieved in Haskell?
How about Control.Monad.Loops.iterateM_? This is slightly neater as it avoids explict recursion.
iterateM_ :: Monad m => (a -> m a) -> a -> m b
saveThreadFunc :: TQueue String -> Int -> IO ()
saveThreadFunc queue = iterateM_ $ \lastBackupTime -> do
newLine <- atomically $ readTQueue queue
now <- round `fmap` getPOSIXTime :: IO Int
writeFile "content.txt" newLine
let makeNewBackup = now >= lastBackupTime + 86400
when makeNewBackup (backupContent now newLine)
return (if makeNewBackup then now else lastBackupTime)
Replace forever with explicit recursion.
foo :: Int -> IO ()
foo n = do
use n
foo (n+1)
Of course, you can use any type for your state instead of Int.
Otherwise, if you really want the mutable state:
foo :: IO ()
foo = do
r <- newIORef (0 :: Int)
forever $ do
n <- readIORef r
use n
writeIORef r (n+1)
Unless you really need mutability for some other reason, I'd not recommend the second option.
Adapting the above idea to the concrete code:
saveThreadFunc :: Int -> TQueue String -> IO ()
saveThreadFunc lastBackupTime queue = do
newLine <- atomically $ readTQueue queue
now <- round `fmap` getPOSIXTime :: IO Int
writeFile "content.txt" newLine
let makeNewBackup = now >= lastBackupTime + 86400
if makeNewBackup then do
backupContent now newLine
saveThreadFunc now queue
else
saveThreadFunc lastBackupTime queue
The usual way to add state to a monad is using StateT from Control.Monad.Trans.State.Strict in the transformers package (part of the Haskell Platform). In this case, you would change the type of saveThreadFunc:
saveThreadFunc :: TQueue String -> StateT Int IO ()
You'd have to Control.Monad.Trans.lift the actual IO things to StateT Int IO, and then in the end evalStateT to turn the whole thing into IO a.
This approach is perhaps more modular than the the iterateM_ one Tom Ellis suggests (although that's something of a matter of taste), and will generally be optimized better than the IORef version chi suggests you avoid.

Difficulty performing actions in a finite loop with user input

I'm using Allegro CL Express on a Mac and I'm not sure if the program is having difficulties, or my code is poorly formed. I'm trying to take 4 user input integers and then add them after the last value is entered
Desired outcome:
(stuff)
Enter a number: 4
Enter a number: 3
Enter a number: 2
Enter a number: 1
10
Here's what I currently have:
(defun stuff ()
(loop repeat 4
sum (format t "Enter a number: ")
(parse-integer (read-line))))
EDIT:
After some great help, here is what I have:
CG-USER(18): (defun stuff ()
(loop repeat 4
sum (progn
(format t "Enter a number: ")
(parse-integer (read-line)))))
STUFF
CG-USER(19): (stuff)
Enter a number: 1
It just hangs after I enter an integer and press return.
Using a compiler helps. Look what SBCL says when evaluating your form:
CL-USER> (defun stuff ()
(loop repeat 4
sum
(format t "Enter a number: ")
(parse-integer (read-line))))
; in: DEFUN STUFF
; (LOOP REPEAT 4
; SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER (READ-LINE)))
;
; caught ERROR:
; during macroexpansion of (LOOP REPEAT 4 ...). Use *BREAK-ON-SIGNALS* to
; intercept.
;
; (PARSE-INTEGER
; (READ-LINE)) found where a LOOP keyword or LOOP type keyword expected
; current LOOP context: SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER
; (READ-LINE)).
;
; compilation unit finished
; caught 1 ERROR condition
STUFF
The most important part there is
; (PARSE-INTEGER
; (READ-LINE)) found where a LOOP keyword or LOOP type keyword expected
; current LOOP context: SUM (FORMAT T "Enter a number: ") (PARSE-INTEGER
; (READ-LINE)).
So it's getting (PARSE-INTEGER (READ-LINE)) where a loop keyword or type is expected. Why's that? The documentation for loop should tell us. sum is a numeric accumulation:
numeric-accumulation::= { count | counting | sum |
summing | maximize | maximizing |
minimize | minimizing }
{form | it}
[into simple-var] [type-spec]
So, after sum, there should be a single form. You'd just need to wrap your prompt and the call to read-line in, e.g., a progn to produce a single form:
(defun stuff ()
(loop repeat 4
sum (progn
(format *query-io* "Enter a number: ")
(parse-integer (read-line *query-io*)))))
Note also that I used the stream *query-io* for input and output. You don't have to do that, but it's probably a bit more robust, since:
The value of *query-io*, called query I/O, is a bidirectional stream
to be used when asking questions of the user. The question should be
output to this stream, and the answer read from it.

While loop in Haskell with a condition

I'm having a little Haskell Situation over here. I'm trying to write two functions with monads.
First one is supposed to iterate through a function as long as the condition is true for the input / output of the function. Second one is supposed to use the first one to take a number as input and write it as output until you enter a space.
I'm stuck with this, any help?
module Test where
while :: (a -> Bool) -> (a -> IO a) -> a -> IO a
while praed funktion x = do
f <- praed (funktion x)
if f == True then do
y <- funktion x
while praed funktion y
else return x
power2 :: IO ()
power2 = do putStr (Please enter a number.")
i <- getChar
while praed funktion
where praed x = if x /= ' ' then False else True
funktion = i
import Control.Monad
while :: (a -> Bool) -> (a -> IO a) -> a -> IO a
while praed funktion x
| praed x = do
y <- funktion x
while praed funktion y
| otherwise = return x
power2 :: IO ()
power2 = do
putStr "Please enter a number."
i <- getChar
let praed x = x /= ' '
let f x = do
putChar x
getChar
while praed f '?'
return ()
Some notes:
Using if x then True else False is redundant, it's equivalent to just x.
Similarly if x == True ... is redundant and equivalent to if x ....
You need to distinguish between IO actions and their results. For example, if yo do
do
i <- getChar
...
then in ... i represents the result of the action, a character, so i :: Char. But getChar :: IO Char is the action itself. You can view it as a recipe that returns Char when performed. You can pass the recipe around to functions etc., and it is only performed when executed somewhere.
Your while called funktion twice, which probably isn't what you intend - it would read a character twice, check the first one and return the second one. Remember, your funktion is an action, so each time you "invoke" the action (for example by using <- funktion ... in the do notation), the action is run again. So it should rather be something like
do
y <- funktion x
f <- praed y
-- ...
(My code is somewhat different, it checks the argument that is passed to it.)
For a pure version:
{-# LANGUAGE BangPatterns #-}
while :: (a -> Bool) -> (a -> a) -> a -> a
while p f = go where go !x = if p x then go (f x) else x
test1 :: Int
test1 = while (< 1000) (* 2) 2
-- test1 => 1024
for monadic:
import Control.Monad
whileM :: (Monad m, MonadPlus f) => (a -> m Bool) -> m a -> m (f a)
whileM p f = go where
go = do
x <- f
r <- p x
if r then (return x `mplus`) `liftM` go else return mzero
test2 :: IO [String]
test2 = whileM (return . (/= "quit")) getLine
-- *Main> test2
-- quit
-- []
-- *Main> test2
-- 1
-- 2
-- 3
-- quit
-- ["1","2","3"]
power2 :: IO (Maybe Char)
power2 = whileM (return . (/= 'q')) getChar
-- *Main> power2
-- q
-- Nothing
-- *Main> power2
-- 1
-- 2
-- 3
-- q
-- Just '\n'
see also:
http://hackage.haskell.org/package/monad-loops, http://hackage.haskell.org/package/loop-while, http://hackage.haskell.org/package/control-monad-loop.
http://www.haskellforall.com/2012/01/haskell-for-c-programmers-for-loops.html

Resources