I have doubts to do this exercise. I have the solution (which is apparently wrong) but I could not understand:
Write a program that reads integers from the default input device, one per line, to a negative or zero universe, and prints an average and the largest of the read values.
My code:
a6 ::Int -> Float ->Int->Int-> IO()
a6 cBigger average2 sum2 cCount = do
c <- getLine
let digit = read c :: Int
let sum = sum2 + digit
let average = fromIntegral sum2/ fromIntegral cCount
if (digit <=0)
then putStrLn("Bigger :" ++show(cBigger)++ "average "++show(cAverage))
else
if digit > cBigger
then a6 digit average sum (cCount+1)
else a6 cBigger average sum (cCount+1)
As I do not understand much Haskell I have doubts of how to do.
Although a little off topic, I thought I would comment on separation of concerns and modularity.
Usually, we try to keep the pure parts of the program separate from the impure (IO) parts.
We can read a list of Ints with impure code, and then process it with a pure function to find the max, sum, and length in order to compute the average.
Below, readInts reads Ints from stdin until it reads a non-positive value, returning the positive Ints in a list (in IO). maxSumLength takes the current maximum, sum, and length of the elements processed so far
as a tuple, and the next element to process, and returns a new tuple with the next element folded in. Finally, main reads the list of Ints, and applies a strict left fold (foldl') using maxSumLength and an initial state of (0, 0, 0) to compute the final maximum, sum, and length. It then prints the maximum and the average from the sum and length.
module Main where
import Data.List ( foldl' )
readInts :: IO [Int]
readInts = do
i <- read <$> getLine
if i <= 0
then return []
else (i:) <$> readInts
maxSumLength :: (Int, Int, Int) -> Int -> (Int, Int, Int)
maxSumLength (m, s, l) x = (max m x, s+x, l+1)
main :: IO ()
main = do
(m, s, l) <- foldl' maxSumLength (0, 0, 0) <$> readInts
putStrLn $ "max=" ++ show m ++ ", avg=" ++ show (fromIntegral s / fromIntegral l)
This code is more modular than before. We could reuse readInts in other programs that need a list of Ints. Also, the pure part of the algorithm no longer cares where the list of Ints comes from. However, there is a problem with this code. When written this way, the entire list has to be buffered in memory before the pure code can start processing it, even though the processing code can consume the input as it arrives.
This is where the conduit package can help. The conduit package allows a stream to be produced by an impure Source and connected to a pure Consumer, and allows the pure code to be interleaved with the impure code. The conduit-combinators package provides combinators that allow streams to be treated much like lists (in particular, foldlC allows us to perform a strict left fold over a conduit stream instead of a list).
In the code below, the readInts function is now a Source of Ints that runs in the IO monad. It uses the repeatWhileMC combinator to perform the looping and the termination test. The pure maxSumLength is unchanged; however, in main, rather than use foldl', we use foldlC to fold over the conduit stream.
module Main where
import Conduit
readInts :: Source IO Int
readInts = repeatWhileMC (read <$> getLine) (> 0)
maxSumLength :: (Int, Int, Int) -> Int -> (Int, Int, Int)
maxSumLength (m, s, l) x = (max m x, s+x, l+1)
main :: IO ()
main = do
(m, s, n) <- runConduit (readInts =$= foldlC maxSumLength (0, 0, 0))
putStrLn $ "max=" ++ show m ++ ", avg=" ++ show (fromIntegral s / fromIntegral n)
This code will interleave pure maxSumLength with the impure readInts so that the Ints are consumed as they are created, but without sacrificing modularity. The readInts stream can be used in other programs that need a stream of Ints, and the pure code still no longer cares where the Ints are coming from.
While not optimal, your program is almost working. Here's some minor fixes and cleanups. I tried to keep your original code when possible, even if there might be better solutions.
First, you are using cAverage which is not defined. This error can be easily fixed.
The average2 parameter is pointless, since it is unused -- let's remove it.
Some lets can be moved to the branches where we actually use those variables.
We can also perform a minor refactoring and compute the new bigger value using a conditional, instead of using a conditional to perform two different recursive calls. (It would be even better to use the max function, though.)
Consider to rename "bigger" to "biggest", or "greatest", or "maximum". It sounds better to me.
a6 :: Int -> Int -> Int -> IO()
a6 bigger oldSum count = do
c <- getLine
let digit = read c :: Int
if digit <= 0
then let average = fromIntegral oldSum / fromIntegral count :: Double
in putStrLn ("Bigger: " ++ show bigger ++ ", average: " ++ show average)
else let newBigger = if digit > bigger then digit else bigger
newSum = oldSum + digit
in a6 newBigger newSum (count+1)
Related
I am beginner to Haskell Im trying to make neuron to do that I need to generate random numbers for the weights of neurones but I'm stuck at function random it provokes an infinite loop
I can't figure where the problem is, in addition when I ask in terminal when compiled take 3 random it always give me the same numbers I want it to take different random numbers each time
l = [1,0,1,1,0,0,1,0]
toDec :: [Int] -> Float
toDec [] = 0
toDec (x:xs) = fromIntegral x+2*(toDec xs)
next :: [Int] -> [Int]
next xs = xs'
where xs' = v:(init xs)
v = xor (last xs) (xs!!4)
random :: [Float]
random = ran l
where ran l = ( (toDec l) / 255.0):(ran (next l))
-- simple neuron
data Neuron = Neuron [Float]
deriving (Read,Show)
n = Neuron (take 3 random)
You function works perfectly fine: it generates an infinite list of pseudorandom numbers.
(It's not a particularly good PRNG – for serious applications you should better use a library, random-fu is very extensive – but for educational purposes it's fine.)
But well, you need to be clear what this actually means. Because random is just a value of type [Float], it of course is always the same list. You can still use it for obtaining multiple different finite lists, by splitting up the single infinite one:
n₀, n₁, n₂ :: Neuron
(n₀:n₁:n₂:_) = Neuron <$> splits 3 random
-- | #splits n l# gives a list of sublists of #l#, each of which has length #n#.
-- If the sublists are concatenated again, you get back #l#.
splits :: Int -> [a] -> [[a]]
splits nPerList l = case splitAt nPerList l of
(h,[]) -> [h]
(h,t) -> h : splits nPerList t
If you want something that behaves like the “random functions” in imperative languages, i.e. something that gives a different value each time it's called... well that's not a function then, because a function must for given input yield always the same result. However you can implement it as an action in a suitable monad. In an imperative language, there would be an implicit state of the PRNG. You can have that in Haskell too, except the state is explicit (which actually has a lot of advantages for reliability).
import Control.Monad.Trans.State
type RandSupply = State [Float]
oneRandom :: RandSupply Float
oneRandom = do
~(h:t) <- get -- This is a bit of a hack†
put t
return h
randomNeuron :: Int -> RandSupply Neuron
randomNeuron nWeights = Neuron <$> replicateM nWeights oneRandom
Then you can write code like
import Control.Monad
(`evalState`random) $ do
...
n <- randomNeuron 3
...
n₅ <- randomNeuron 5
...
and n and n₅ will have different weights, because the state of the supply-list has changed in between.
†The irrefutable match ~(h:t) means that the action can fail badly if you try to use it with only a finite supply of random numbers. Again: the proper thing to do is to use a library for random numbers, rather than rolling your own.
Haskell is challenging! What I figured out so far is that I can do the following to simulate a for-loop in Haskell to get a list of numbers from the user:
myList <- sequence [putStr "Enter an integer: " >> (
\s -> read s :: Int) <$> getLine | t <- [1..5]]
Great! So myList contains five integers that I have entered. Great! But here's the catch. Instead of a for-loop that iterates five times (or any finite number of times) how can I convert the above to the equivalent while-loop?
So what I'm thinking of is this, but it won't work, unfortunately. Is there some "magic" way to make it work?
takeWhile (\x -> x > 0) $ sequence [putStr "Enter an integer: " >> (
\s -> read s :: Int) <$> getLine | t <- [1..]]
The problem is that (\x -> x > 0) works with Ints. (Or any Num type.) But what's coming from that list is really a bunch of IO Ints. x > 0 returns a Bool. I need a function that returns an IO Bool? I'm a little lost. Can someone point the way to Haskell enlightenment for me?! Studying this on my own isn't exactly easy!!! Thank you so much!!!
You cannot write this program with a sequence of an infinite list of IO actions. Any operations you perform "outside" of the sequence will be unable to inspect its contents, and any operations inside the sequence will be unable to stop it from continuing.
Instead, you must write an IO action which reads an Int, inspects it, and decides whether to continue or to stop at that time.
positiveInts :: IO [Int]
positiveInts = do
putStr "Enter an integer: "
i <- readLn
if i <= 0
then pure []
else (i:) <$> positiveInts
#amalloy's answer is great. It's kind of conditional sequencing.
Perhaps we may attempt generalizing it further by inventing takeWhileM (basically conditional sequencing) which sequences only an initial part of an indefinitely long list of actions while a predicate satisfies.
takeWhileM :: Monad m => (a -> Bool) -> [m a] -> m [a]
takeWhileM f (a:as) = a >>= \n -> if f n then (n:) <$> takeWhileM f as
else pure []
So for this particular case i run it like
λ> takeWhileM (> 0) . repeat $ putStr "Enter an integer:" >> readLn
Enter an integer:1
Enter an integer:2
Enter an integer:3
Enter an integer:4
Enter an integer:5
Enter an integer:0
[1,2,3,4,5]
I want to have a function that reads arbitrary int's until the number '0' is inserted, and then presents the numbers inserted in an ordered list.
For that i wrote this function:
import Data.List
readIntegers :: IO()
readIntegers = do
putStrLn "insert a number: "
num<-getLine
let list = ordList ((read num :: Int):list)
if (read num == 0)
then print list
else readIntegers
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
This compiles just fine, but when i insert the number '0', it gives me this error:
*** Exception: <<loop>>
What am i doing wrong ?
As #phg points out, you are essentially constructing an infinite list, and actually evaluating it causes the loop error. A simple implementation to resolve this issue is to define a helper function which takes an additional parameter - a list to store all the inputs read in from the screen, like so:
readInteger :: IO ()
readInteger = readInteger' []
where
readInteger' x = do
putStrLn "insert a number: "
num<-getLine
if ((read num :: Int) == 0)
then print $ ordList x
else readInteger' $ (read num :: Int):x
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
Please note that the above is essentially just an implementation of #phg's answer, but with some changes to your original logic. Firstly, since 0 is a sentinel value, we shouldn't be appending that to our list. Second, we do not need to sort the list every single time we are adding a value to it. Sorting once at the time of printing/passing to another function is sufficient.
Demo
If you want to read an unspecified number of integers without prompting for user input and cut it off the moment you encounter 0, you would probably do well to use getContents, which will read everything from the standard input as a single string, lazily.
Then, it is a simple matter of parsing it to a list of numbers and doing what you want with it, like so:
readIntegers :: ()
readIntegers = do
a <- getContents
let b = ordList $ takeWhile (/= 0) $ map (\x -> read x :: Int) $ words a
mapM (putStrLn . show) b
where ordList ::[Int]->[Int]
ordList [] = []
ordList xs = sort xs
let list = ordList ((read num :: Int):list)
This is basically a recursive definition of a list of the form [x, x, ...] (like if you wrote an equation saying x = 1 + x). That is perfectly fine by itself, since Haskell is lazy; however, if you try to print list (aka "solve the equation"), it will fail, since it will try to print infinitely many numbers.
You probably have a misconception about the workings of the (:) operator. Haskell functions will never perform an assignment operation and concatenate num onto list by changing it, like in imperative languages. There are only pure functions.
If you want to accumulate all numbers, you should try to come up with a recursive definition of readIntegers, keeping its state (the list) in an additional parameter (there are also more sophisticated ways, hiding the state passing, but more complicated to use for a beginner).
For a more sophisticated solution, note that this is an unfold and you can use unfoldM from Control.Monad.Loops to implement it:
import Control.Monad.Loops (unfoldM)
readInts :: IO [Int]
readInts = unfoldM $ fmap (check . read) getLine
where check x = if x == 0 then Nothing else Just x
This has the nice property that it returns the list in the order in which it was read.
Im trying to write a simple function to learn the IO monad in Haskell. The function is supposed to take the sum of some given integers from the console but when the function has run for example 4 times it says "1*** Exception: Char.digitToInt: not a digit '\n'"
import Data.Char
readInts :: IO ()
readInts = do
putStrLn "Choose nr of ints to sum."
c <- getChar
let i = digitToInt c
-- code.
let sum = getInts i
let str = "\nSum is: " ++ [intToDigit i].
putStrLn str
getInt :: IO Int
getInt = do
c <- getChar
return (digitToInt c)
getInts :: Int -> IO Int
getInts n = if n == 0
then return 0
else
do i <- getInt
j <- getInts
return (i+j)
Can somebody please explain where my recursion is going wrong?
You're simply using the wrong tools to convert between "keyboard data" and numbers. Has little to do with IO.
intTodigit, as the name says, acts on single digits / characters, not on general numbers. What you want is to read / print entire strings, which can handle multi-digit numbers. Replace getChar with getLine, digitToInt with read, and [intToDigit i] with show i. Then it should work fine.
However, it would be better to make some more simplifications.
getInt basically exists already, though in more general form: readLn gets a line from stdin and inteprets it as the required type.
getInts is implemented more complicately than necessary. Explicit recursion over a counting variable (BTW, it has to be getInts (n-1) in the recursion) is ugly; such looping is obviously so common that there exists a standard solution (you need to import Control.Monad) for it which looks alot like loops in imperative languages you might be used to:
getIntsAndSum :: Int -> IO Int
getIntsAndSum n = fmap sum . forM [1 .. n] $ \k -> do
i <- getInt
return i
which can in fact be further simplified to
fmap sum . forM [1 .. n] $ \_ -> getInt
because do blocks a just an optional construct to help you chain actions, but when there's only one action you can simply write that on its own.
Ideally, you would not have to first ask for the number of numbers at all: just gather all numbers you're given, and sum them up. This works, as jamshidh said, very simply with interact.
main = interact processInput
where processInput allInput = show (sum allNumbers)
where allNumbers = map read . lines allInput
and that's it! Nothing else needed. In fact, this can be written yet simpler: you basically have just one simple data-flow pipeline.
main = interact $ show . sum . map read . lines
getChar gets every char, including any "\n" that you type in (which you need to submit the answer). Try filtering these out.
A better way to solve this could be to use "interact" to get the user input, and break apart the data using lines. That way the user could input multi digit numbers, and the "\n"'s would be removed.
The following sums numbers entered at the command line (without any prompting, end inputting by typing ^d).
main = interact (show . sum . fmap read . lines)
WIth the help of the members of this community, especially by Daniel I can mke the list of pascal triangles number. BUt Whenever i want to display the triangle as a triangle shape it gives error like: parse error on input 'import'. I expct some1 will cme forward to explain me this. the code is below:
import Text.Printf
pascal :: [[Integer]]
pascal = iterate (\prev -> 1 : zipWith (+) prev (tail prev) ++ [1]) [1]
prettyPascal :: Int -> IO ()
prettyPascal n = mapM_ (\r -> printf "%*s\n" (div (longest + length r) 2) r) rows
where rows = map (unwords . map show) $ take (n + 1) pascal
longest = length $ last rows
Summary answer:
module PrettyPascal where -- good practice, means you can combine it with other code
import Text.Printf
pascal :: [[Integer]]
pascal = iterate (\prev -> 1 : zipWith (+) prev (tail prev) ++ [1]) [1]
where must be further indented than the line before, and longest must line up with rows:
prettyPascal :: Int -> IO ()
prettyPascal n = mapM_ (\r -> printf "%*s\n" (div (longest + length r) 2) r) rows
where rows = map (unwords . map show) $ take (n + 1) pascal
longest = length $ last rows
You could do main = prettyPascal 10, but you might prefer:
main =
putStrLn "How many rows of Pascal's triangle would you like to see?"
>> readLn >>= prettyPascal
(If you're using ghci or Hugs, you don't need a main, you can just type prettyPrint 10 at the prompt.)
Other points from discussion below:
Haskell is case sensitive, so it has to be prettyPascal, not PrettyPascal.
When you're using a type class (as in your other code), you need Eq a => instead of Eq a ->
Use copy-and-paste to avoid typing errors
Save your functions in a file called something like PrettyPascal.hs.
Then load your functions in ghci by typing :l PrettyPascal.
Sometimes if you're not sure whether it's your compiler or your code, copy-and-paste to codepad.org for a second opinion. (You could also download and install the fast Hugs compiler which does Haskell 98 and multiparameter typeclasses, but not lots of ghc extensions.)