Haskell: writing the result of a computation to file - haskell

I have a function which creates a tuple after computation, but I would like to write it to file.
I know how to write to a file using writeFile, but do not know how to combine the computation and monads IO together in the type signature.
This is my code.
invest :: ([Char]->Int->Int->([Char], Int) )
-> [Char]->Int->Int->([Char], Int)
invest myinvest x y = myinvest x y
myinvest :: [Char]->Int->Int->([Char], Int)
myinvest w x y
| y > 0 = (w, x + y)
| otherwise = error "Invest amount must greater than zero"
where
I have a function which computes the maximum value from a list, but I want this function to receive input from a file, and then perform the computation of maximum value.
maximuminvest :: (Ord a) => [a] -> a
maximuminvest [] = error "Empty Invest Amount List"
maximuminvest [x] = x
maximuminvest (x:xs)
| x > maxTail = x
| otherwise = maxTail
where maxTail = maximuminvest xs
Please help.
Thanks.
[Edit]
My new question is at below.
The first and second question can be solve through function composition but when i try it say type mismatch.
I have check it but i couldn't find any errors.
invest :: ( [Char]->Int->Int->([Char], Int) ) -> [Char]->Int->Int-> ([Char], Int)
invest theinvest x y = theinvest x y
theinvest :: [Char]->Int->Int-> ([Char], Int)
theinvest w x y | y > 0 = (w, x + y)
| otherwise = error "Invest amount must greater than zero"
savefile :: ([Char], Int) -> IO()
savefile (x, y) = do
let name = fst (x, y)
let temp = snd(x, y)
let amount = show temp
writeFile "C:\\Invest.txt" (name ++ " " ++ amount)
test = savefile . theinvest "asd" 1234 234
The error message is
ERROR - Type error in application
* Expression : savefile . invest theinvest "234" 234 234
Term : invest theinvest "234" 234 234
Type : ([Char],Int)
* Does not match : a -> b
Please help. My return type is ([Char],Int). Why it complaint as a -> b ? Thanks
I solve this using command like savefile (invest theinvest "asd" 12 12) but why the operator doesn;t works ?
My fourth question is i have something like this ["peter","1000","michell","2000","kelly","3000"] and i would like to convert to [("peter",1000),("michell", 2000),("kelly",3000)]
The reading of file content is ok but i want to filter the string and get the number only. For instance, a file that has "peter 100\nasd 200"
I would like to drop the alphabet and remain the integer here.
I just want the [100, 200] to be the argument the function.
Please help.
Thanks.

You might want to do something like
main = do
c <- computation
writeFile "filename" (show c)
to write out to the file using a Show instance for the result of the computation. If your types are easy enough, this is both human-readable and readable for Haskell restoring the value again.
For the second question, suppose your file stores values as
[1.5,2.3,5.1,6.3,9.8]
then it is blindingly easy to read them in and perform a computation:
main = do
str <- readFile "filename"
return $ computation (read str)
should do it. If instead you have your data with an item per line, or in a CSV file, or something else, it gets a little bit more involved. For CSV there is Text.CSV up on Hackage that seems to do the trick.

For your question about funcion composition, you have to remember that function application binds very strongly - more strongly than composition. So your problematic expression parses as
savefile . (theinvest "asd" 1234 234)
The type of (theinvest "asd" 1234 234) is ([Char],Int) which is not a function and can't be composed. That's what the type error is about.
You want to apply savefile to this, and the easiest is to just remove the . and put the parentheses in. Another way is to replace the . by $ which is a weakly binding function application operator. And if you really, really want a period in there, you could use (savefile . theinvest "asd" 1234) 234 but that's very silly and unclear, in my opinion.

creates a tuple after computation, but I would like to write it to file.
The simplest way is with 'show', which gives a text-based serialization method for most Haskell data types.
writeFile "foo" (show c)
For more efficient serialization, there is Data.Binary:
encodeFile "foo" c
Which will write it in a binary format.

for your last question you would use lines to get ["peter 2000", Joe "50"] etc. then use filter to drop non numerics.
so
filter Data.Char.isDigit . lines
should do it(Note: code written without being tested may not be 100%, and it doesn't handle the case of "7Bill 400" correctly.)

Related

How can you use the result of a function as a variable in another function in Haskell?

I'm trying to learn how to use Haskell and now I have to make a program that takes a integer n and a string k and every letter of that string will be moved n places to the right in the alphabet. At this moment I've got the next code:
import Data.Char
main = do
x <- read getLine :: Int
y <- getLine
caesar x y
result :: String
rotate :: Int -> Char -> [Char]
rotate a b = [chr ((a + ord b) `mod` ord 'z' + ord 'a')]
caesar :: Int -> String -> ()
caesar moving text= do
rotatespecific moving text 0
putStrLn result
rotatespecific :: Int -> String -> Int -> ()
rotatespecific moving text place = do
if place < length text
then
result ++ rotate (moving (text !! place))
rotatespecific (moving text (place + 1))
else
if place == length text
then
result ++ rotate (moving (text !! place))
But I can't compile it because it still gives me the same error message:
parse error (possibly incorrect indentation or mismatched brackets)
|
28 | result ++ rotate (moving (text !! place))
| ^
But I can't see what's wrong with my syntax. I first thought it had something to do with using a Char as parameter for my function but I was wrong because text !! place should give a char and not a [char]. So what's wrong with what I'm doing?
After some edit I got this, but it still doesn't work:
import Data.Char
main = do
xr <- getLine
let x = read xr :: Int
y <- getLine
putStrLn (rotatespecific (x y 0))
rotate :: Int -> Char -> [Char]
rotate a b = [chr ((a + ord b) `mod` ord 'z' + ord 'a')]
rotatespecific :: Int -> String -> Int -> String
rotatespecific moving text place = do
if place < length text
then do
help <- text !! place
h <- rotate (moving help)
a <- rotatespecific (moving text (place + 1))
b <- h ++ a
return b
else
if place == length text
then do
return rotate (moving (text !! place))
else
return ()
The immediate problem is that every if must have an else. You got a parse error at the end because the parser is expecting more, namely an else for that if place == length text.
When you fix this you will have more problems, because you are treating Haskell like an imperative language, and that's not how she likes to be treated. It seems like you think
result ++ newstuff
will mutate result, adding newstuff to the end of it. But Haskell doesn't mutate. Instead, this expression result ++ newstuff is the list that results when you concatenate result and newstuff, but result itself remains unchanged.
ghci> let result = [1,2,3]
ghci> result ++ [4,5,6]
[1,2,3,4,5,6]
ghci> result
[1,2,3]
rotatespecific must return the rotated string, rather than trying to mutate it into existence. The only way functions may communicate is by returning results computed from their arguments -– they may not manipulate any "global" state like result. A function that returns () is guaranteed to be useless.
rotatespecific :: Int -> String -> Int -> String
Delete the result "global variable" (which does not mean what you think it means) and focus on defining rotatespecific in a way that it returns the rotated string.
I would also recommend commenting out main and caesar for now until you have rotatespecific compiling and working when you test it in ghci.
I feel like this is an appropriate time to just show an example, because there are a lot of little problems. I'm not going to fix logic bugs, but I've fixed your syntax. Hopefully this gets you unstuck.
rotatespecific :: Int -> String -> Int -> String
rotatespecific moving text place =
if place < length text then
-- use let .. in instead of do/bind (<-) in pure functions.
let help = text !! place
-- multiple arguments are given after the function, no parentheses
h = rotate moving help
-- use parentheses around an argument if it is a complex expression
-- (anything more than a variable name)
a = rotatespecific moving text (place+1)
b = h ++ a
in b
else
if place == length text then
rotate moving (text !! place)
else
undefined -- you must decide what String to return in this case.
After you have this function working as intended, and only then, open this sealed envelope. ♥️
rotatespecific :: Int -> String -> String
rotatespecific moving text = concatMap (rotate moving) text

How do I recursively use newStdGen in Haskell? (to get different random results on each iteration)

I use System.Random and System.Random.Shuffle to shuffle the order of characters in a string, I shuffle it using:
shuffle' string (length string) g
g being a getStdGen.
Now the problem is that the shuffle can result in an order that's identical to the original order, resulting in a string that isn't really shuffled, so when this happens I want to just shuffle it recursively until it hits a a shuffled string that's not the original string (which should usually happen on the first or second try), but this means I need to create a new random number generator on each recursion so it wont just shuffle it exactly the same way every time.
But how do I do that? Defining a
newg = newStdGen
in "where", and using it results in:
Jumble.hs:20:14:
Could not deduce (RandomGen (IO StdGen))
arising from a use of shuffle'
from the context (Eq a)
bound by the inferred type of
shuffleString :: Eq a => IO StdGen -> [a] -> [a]
at Jumble.hs:(15,1)-(22,18)
Possible fix:
add an instance declaration for (RandomGen (IO StdGen))
In the expression: shuffle' string (length string) g
In an equation for `shuffled':
shuffled = shuffle' string (length string) g
In an equation for `shuffleString':
shuffleString g string
= if shuffled == original then
shuffleString newg shuffled
else
shuffled
where
shuffled = shuffle' string (length string) g
original = string
newg = newStdGen
Jumble.hs:38:30:
Couldn't match expected type `IO StdGen' with actual type `StdGen'
In the first argument of `jumble', namely `g'
In the first argument of `map', namely `(jumble g)'
In the expression: (map (jumble g) word_list)
I'm very new to Haskell and functional programming in general and have only learned the basics, one thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
Complete code:
import System.Random
import System.Random.Shuffle
middle :: [Char] -> [Char]
middle word
| length word >= 4 = (init (tail word))
| otherwise = word
shuffleString g string =
if shuffled == original
then shuffleString g shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
jumble g word
| length word >= 4 = h ++ m ++ l
| otherwise = word
where
h = [(head word)]
m = (shuffleString g (middle word))
l = [(last word)]
main = do
g <- getStdGen
putStrLn "Hello, what would you like to jumble?"
text <- getLine
-- let text = "Example text"
let word_list = words text
let jumbled = (map (jumble g) word_list)
let output = unwords jumbled
putStrLn output
This is pretty simple, you know that g has type StdGen, which is an instance of the RandomGen typeclass. The RandomGen typeclass has the functions next :: g -> (Int, g), genRange :: g -> (Int, Int), and split :: g -> (g, g). Two of these functions return a new random generator, namely next and split. For your purposes, you can use either quite easily to get a new generator, but I would just recommend using next for simplicity. You could rewrite your shuffleString function to something like
shuffleString :: RandomGen g => g -> String -> String
shuffleString g string =
if shuffled == original
then shuffleString (snd $ next g) shuffled
else shuffled
where
shuffled = shuffle' string (length string) g
original = string
End of answer to this question
One thing that might be relevant which I don't know yet is the difference between "x = value", "x <- value", and "let x = value".
These three different forms of assignment are used in different contexts. At the top level of your code, you can define functions and values using the simple x = value syntax. These statements are not being "executed" inside any context other than the current module, and most people would find it pedantic to have to write
module Main where
let main :: IO ()
main = do
putStrLn "Hello, World"
putStrLn "Exiting now"
since there isn't any ambiguity at this level. It also helps to delimit this context since it is only at the top level that you can declare data types, type aliases, and type classes, these can not be declared inside functions.
The second form, let x = value, actually comes in two variants, the let x = value in <expr> inside pure functions, and simply let x = value inside monadic functions (do notation). For example:
myFunc :: Int -> Int
myFunc x =
let y = x + 2
z = y * y
in z * z
Lets you store intermediate results, so you get a faster execution than
myFuncBad :: Int -> Int
myFuncBad x = (x + 2) * (x + 2) * (x + 2) * (x + 2)
But the former is also equivalent to
myFunc :: Int -> Int
myFunc x = z * z
where
y = x + 2
z = y * y
There are subtle difference between let ... in ... and where ..., but you don't need to worry about it at this point, other than the following is only possible using let ... in ..., not where ...:
myFunc x = (\y -> let z = y * y in z * z) (x + 2)
The let ... syntax (without the in ...) is used only in monadic do notation to perform much the same purpose, but usually using values bound inside it:
something :: IO Int
something = do
putStr "Enter an int: "
x <- getLine
let y = myFunc (read x)
return (y * y)
This simply allows y to be available to all proceeding statements in the function, and the in ... part is not needed because it's not ambiguous at this point.
The final form of x <- value is used especially in monadic do notation, and is specifically for extracting a value out of its monadic context. That may sound complicated, so here's a simple example. Take the function getLine. It has the type IO String, meaning it performs an IO action that returns a String. The types IO String and String are not the same, you can't call length getLine, because length doesn't work for IO String, but it does for String. However, we frequently want that String value inside the IO context, without having to worry about it being wrapped in the IO monad. This is what the <- is for. In this function
main = do
line <- getLine
print (length line)
getLine still has the type IO String, but line now has the type String, and can be fed into functions that expect a String. Whenever you see x <- something, the something is a monadic context, and x is the value being extracted from that context.
So why does Haskell have so many different ways of defining values? It all comes down to its type system, which tries really hard to ensure that you can't accidentally launch the missiles, or corrupt a file system, or do something you didn't really intend to do. It also helps to visually separate what is an action, and what is a computation in source code, so that at a glance you can tell if an action is being performed or not. It does take a while to get used to, and there are probably valid arguments that it could be simplified, but changing anything would also break backwards compatibility.
And that concludes today's episode of Way Too Much Information(tm)
(Note: To other readers, if I've said something incorrect or potentially misleading, please feel free to edit or leave a comment pointing out the mistake. I don't pretend to be perfect in my descriptions of Haskell syntax.)

haskell : How to report an error for my function

this is an expansion to my last question here: basic haskell : Copying elements
however when an invalid input is added then I want it to print out an error message saying "negative value" or something similar. Is this possible in haskell?
working code:
copy :: Int->a->[a]
copy 0 _ = []
copy y a = [a]++(copy (y-1) a)
final line:
copy b c = error "negative value"
Because partial functions make me sad, I'd suggest doing something more along the lines of
copy :: Int -> a -> Maybe [a]
copy 0 _ = Just []
copy n a | n < 0 = Nothing
| otherwise = fmap (a:) (copy (n-1) a)
We've swapped out that if for a "guard"
foo bar | baz = quux
| ...
is just
foo bar = if baz then quux else ...
Note that I also changed your code a little,
[a] ++ copy (y-1) a ====> fmap (a:) (copy (y-1) a)
You can think of (:) as append.
1 : [2, 3] ==> [1, 2, 3]
It's the preferred alternative to [1] ++ [2, 3]. Say it out loud as "cons", like "construct". We can write this with an operator section
(a:) ==> \x -> a : x
Next we use this wonky fmap function. Think of fmap like this
fmap f Nothing = Nothing
fmap f (Just x) = Just (f x)
So it unwraps a Just and applies a function before rewrapping the result. So our final code returns Nothing if our number is negative, otherwise, just the list.
Why aren't I recommending error? Well because error will blow up your whole program with pretty minimal information and it's a bad idea to try to catch it. Haskell doesn't even mandate that it's possible to do so, GHC just implements error in such a way that it's possible. In other words, you have little chance to recover.
This isn't a big deal for 10 lines of code, but I've spent upwards of 6 hours searching for the offending call to a function using error. It's much faster to debug and more idiomatic haskell.
You can do this with guards
copy :: Int -> a -> [a]
copy n x
| n < 0 = error "negative value"
| n == 0 = []
| otherwise = x : copy (n - 1) x
However, if this fails then it will likely crash your program. A better way is to use the Maybe type:
copySafe :: Int -> a -> Maybe [a]
copySafe n x
| n < 0 = Nothing
| otherwise = Just (copy n x)
Then you can use it as
main = do
putStrLn "Enter a number:"
nStr <- getLine
let n = read nStr :: Int
maybeXs = copySafe n n
case maybeXs of
Nothing -> putStrLn "You entered a negative number!"
Just xs -> print xs
This style forces you to consider both cases of copySafe, either it can fail on a negative value or it can return a valid list. It doesn't crash your program and the error handling is enforced by the type system.
look at http://www.haskell.org/haskellwiki/Error_vs._Exception
for example
copy b c = if c > b then error "negativ value"

Input types in Haskell

I would like to ask question. I am biginner in Hakskell and I have some diffictulties with very simple program, which should tell me if divident % divider == 0.
I have this code:
f::Integer -> Integer -> Bool
f x y = if ((x `mod` y) == 0) then True
else False
main = do putStrLn "Set up dividend"
x <- getLine
putStrLn "Set Up divider"
y <- getLine
f read x::Int read y::Int
but when I want to run it, I've got an error:
Couldn't match expected type `Int' with actual type `m0 b0'
Expected type: m0 a0 -> m0 b0 -> Int
Actual type: m0 a0 -> m0 b0 -> m0 b0
In a stmt of a 'do' block: putStrLn "Set up dividend"
In the expression:
do { putStrLn "Set up dividend";
x <- getLine;
putStrLn "Set Up divider";
y <- getLine;
.... } ::
Int
and I have really no idea, what is wrong. I've also tried f x y (not f read x::Int .....) without any results. I must do something wrong. I know there are many topics about this problem, but nothing helped me. I am missing something.
The problem is in your final line:
f read x::Int read y::Int
This code is basically saying f read x read y, which is of type Int and where f read x is also of type Int. You have to add parentheses so that f is applied properly and that the type annotations are used on the correct terms. You get:
f ((read x) :: Int) ((read y) :: Int)
-- or with fewer parentheses, but meaning the same thing:
f (read x :: Int) (read y :: Int)
Also the if-statement in your definition of f is unnecessary, why not use:
f x y = (x `mod` y) == 0
f read x::Int read y::Int
This applies the function f to the arguments read, x, read and y. It's also saying that the result of f read y should be an Int and that result of the whole thing should be an Int as well. That's obviously not what you want. What you want is to apply f to the results of read x and read y, so you need parentheses around those.
Another problem is that f takes Integers as arguments, but you're telling read to give you Ints. You can fix that by changing Int to Integer or you can remove the type annotations altogether as they can be inferred. You could also change the type of f to accept any type of Integral, so that it works with both Int and Integer.
Lastly the type of main needs to be IO (), but your definition evaluates to a Bool. Maybe you want to print the Bool?
The combination of getLine and read can be simplified to readLine by the way.
So you could do:
main = do putStrLn "Set up dividend"
x <- readLine
putStrLn "Set Up divider"
y <- readLine
print $ f x y
On a first glance you need to use f (read x::Int) (read y::Int) because in your case you are passing functions to you f. I suggest you to take a look at Learn you Haskell for gread good, the input/output chapter in detail. It is one of the best, newbie friendly ressources out there as far as I know.

Problem with haskell programm (Type errors )

--Standered Diviation
module SD where
diviation:: IO()
diviation =
do
putStrLn ("Enter Students Marks")
marks <- getLine
let m = ( read marks)::[Float]
let x = sum' m
let mean = (fromIntegral x)/(fromIntegral $ length )
let len = (read (length(m)))::Float
let divia = divi mean l
let std = map (^2) divia
let stdd = xx length(m-1) m
let final = map sqrt stdd
let tot = sum final
if(m==[])
then
putStrLn("empty List" ++ show(tot))
else do
putStrLn("The Standered Divation is" ++ (show(tot)))
sum' :: (Num a) => [a] -> a
sum' = foldl (+) 0
avg::Float->Float->Float
avg a b = (fromIntegral a)/(fromIntegral b)
divi::Float->[Float]->[Float]
divi a xs = [x-a | x <- xs]
xx::Float->[Float]->[Float]
xx a xs = [x/a|x<-xs]
i can not figure out what's wrong with this program. is shows an error like this
ERROR file:.\SD.hs:11 - Type error in application
*** Expression : read (length m)
*** Term : length m
*** Type : Int
can you guys please point me out problem in this program, thank you
* Does not match : [Char]
There are a few things going on in your code that you might want take a look at. You have:
let stdd = xx length(m-1) m
which will not typecheck. I think you meant:
let stdd = xx (length m-1) m
(Edit: actually, that won't check either due to the type signature for xx. (Why not?)) This line:
let mean = (fromIntegral x)/(fromIntegral $ length )
is a Num divided by a function.
In this line:`
let std = map (^2) divia
what is the type of divia, and what is the type of (^2)?
Finally, what actually happens in the case of the empty list, or even a singleton list?
As an aside, you might want to consider which parts of your program really need to live inside main. As it stands, you're
Printing a line
Reading input
Computing the standard deviation
Printing the result of that computation
Why not factor out a standardDev function? That might make your main function shorter and clearer. Writing pure functions also allows you to test your functions in the REPL more conveniently. When I code, I find it very helpful to build short, obviously correct functions, compose them in order to obtain tge desired behavior, and dump the result into the IO monad only at the very last moment.
The function read has type String -> 'a ; your error tells you that length m has type Int, while read is waiting for a String. You might want to use genericLength from Data.List:
let len = Data.List.genericLength m :: Float

Resources