Haskell Input Output - haskell

Is it possible using's Haskell's input and output to be able to capture and store user entered data into variables?
For example if user was asked a question:
Enter your firstname: Ben,
then firstname = Ben,
Enter your surname: Davies,
then surname = Davies
And finally a print statement to concatenate the 2 variables ie. firstname ++ surname = Ben Davies?
Thanks in advance for the help!

Yes, it is possible.
main = do
putStrLn "Enter your first name"
firstName <- getLine
putStrLn "Enter your last name"
lastName <- getLine
putStrLn $ "Your full name is " ++ firstName ++ " " ++ lastName

Yes, it's easy to do that. See this example

Related

How can I get an modulo of a calculation in Haskell?

I am simply trying to get the Unixtime of the current day. For that I wanted to get the modulo of the current time divided by the timespan of one day. .
yourUnixTime = k / 86400
modunix = mod yourUnixTime 1
main = do
putStrLn "give me your time"
k <- readLn
putStrLn $ "time: " ++show (modunix yourUnixTime)
This is my current code. So why does my code not work?
It says "Variable not in scope: k" I also tried to put a "k" between the "yourUnixTime" and the equal sign, didnt work either (with even more errors I can't understand). So the answer I am hoping for is how I can fix it and/or what other solutions are there.
You are trying to use the variable k before it has been defined or initialized.
Here is the modified version of the code
main = do
putStrLn "Enter the current time:"
k <- readLn
let (unixTime, modUnix) = k `divMod` 86400
putStrLn $ "Unix time of the current day: " ++ show modUnix

Haskell nested where clauses

I am a beginner coder in haskell, while doing an exercise from the first chapter of this amazing book: http://book.realworldhaskell.org/read/getting-started.html
I came across this issue:
-- test comment
main = interact wordCount
where
wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs ++ "\n")
where
ls = lines input
ws = length words input
cs = length input
wonderbox:ch01 manasapte$ runghc WC < quux.txt
WC.hs:5:9: parse error on input ‘where’
Why can I not nest my wheres ?
Since your second where is attached to the wordCount definition, it needs to be indented more than it. (Although you will still have some other errors afterward.)
Others have already answered. I will just add some more explanation.
Simplifying a bit, the Haskell indentation rule is:
Some keywords start a block of things (where,let,do,case ... of).
Find the first word after such keywords and note its indentation. Name the column it occurs the pivot column.
Start a line exactly on the pivot to define a new entry in the block.
Start a line after the pivot to continue the entry started in the previous lines.
Start a line before the pivot to end the block.
Hence,
where
wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs ++ "\n")
where
ls = lines input
ws = length words input
cs = length input
Actually means
where {
wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs ++ "\n")
;
where { -- same column, new entry
ls = lines input
; -- same column, new entry
ws = length words input
; -- same column, new entry
cs = length input
}
}
which treats the second where as a separate definition unrelated to wordCount. If we indent it more, it will work:
where {
wordCount input = show (ls ++ " " ++ ws ++ " " ++ cs ++ "\n")
where { -- after the pivot, same entry
ls = lines input
;
ws = length words input
;
cs = length input
}
}
the indentation was incorrect, here's the working version:
-- test comment
import Data.List
main = interact wordCount
where wordCount input = unlines $ [concat $ intersperse " " (map show [ls, ws, cs])]
where ls = length $ lines input
ws = length $ words input
cs = length input

Haskell Implement an IO code

Im trying to implement an IO code with this concept:
Asking the user for the film title
checks if the film exist, if it does not it returns to the main menu
if it does the programs asks the user for the rating
it checks if its a valid integer, if it does
the program checks if the user has already voted for this film
if he does then asks if he want to modify the rating
if the user's input its not equal to "y" then the program should return to the main menu
if the user type "y" then the database should be updated with the current ratting.
I tried this :
if input /= "y"
then do return (username, database)
else do putStrLn "Your vote will be modified."
but I'm getting this error:
Couldn't match expected type `()'
with actual type `(String, Database)'
In the first argument of `return', namely `(username, database)'
In a stmt of a 'do' block: return (username, database)
In the expression: do { return (username, database) }
Failed, modules loaded: none.
if run it like that:
if input /= "y"
then do return (username, database)
else do putStrLn "Your vote will be modified."
even if the user's input not equals to "y" the database will be updated.
I can't figure out where's the problem with return (username, database)
The code is:
options 7 (username, database) = do
putStrLn "******************"
putStrLn " Rate a film "
putStrLn "******************"
putStrLn ""
putStr "Enter the title of the film or nothing to return to the main menu: "
title <- getLine
if title == ""
then return(username, database)
else do
let filmCheck = findFilm title database
if filmCheck == []
then do
putStrLn "That film does not exists."
return (username, database)
else do
putStr "Enter your rate: "
tempRate <- getLine
case reads tempRate :: [(Integer, String)] of
[(n, "")] -> do
let rate = read tempRate :: Int
let tempFilm = rateFilm username (username, rate) filmCheck
when (checkIfRated username tempFilm == True) $ do
putStrLn "You already voted for this film\n"
putStrLn "Do you want to modify your vote?\n"
putStrLn "Press y to modify or nothing to return to the main menu:"
input <- getLine
if input /= "y"
then do return (username, database)
else do putStrLn "Your vote will be modified."
let database = tempFilm:database
putStrLn "You rating has been sumbited successfully!"
putStrLn (displayFilm tempFilm)
return (username, database)
_ -> do
putStrLn "The number you entered is invalid."
return (username, database)
First, your indentation is wonky. Remember that indentation is significant in Haskell; if you get it wrong, you change the meaning of the code!
At first glance, I think the problem is here:
if input /= "y"
then do return (username, database)
else do putStrLn "Your vote iwll be modified."
The "do" keywords are actually redundant here. But much more importantly, putStrLn returns a (), whereas return clearly returns something else. There's your error.
As another aside, try breaking this into way, way smaller functions. This isn't Java...

Haskell Ending Loop Return

I am trying to stop my program from stopping after the loop in a function ends. Let me first give some background - After a recent failed attempt at Haskell (Here) i have been working through a number of tutorials and have been able to successfully create myself lists containing both a name and priority (Below, working Code - Apologies if the copy/paste has miss-indented it).
module Main where
-- Function Main, gather details, then print
main :: IO ()
main = do info <- gatherInfo
let names = info
putStrLn . unlines . map printDetails $ names
-- Function to Get the Info
gatherInfo :: IO [(String, Int)]
gatherInfo = do putStr "Name: "
name <- getLine
if name == "quit"
then return []
else do priority <- getPri
let info = (name,priority)
otherInfo <- gatherInfo
return $ info : otherInfo
-- Function to get Priority
getPri :: IO Int
getPri = do putStr "Priority: "
input <- getLine
let parsed = reads input
if parsed == []
then do putStrLn "Incorrect Entry, please enter again"
getPri
else return $ fst $ parsed !! 0
--Function to print each detail
printDetails :: (String, Int) -> String
printDetails (name, priorityScore) = "Name: " ++ name ++ "Priority: " ++ show priorityScore
This code will print the following output(incl user input):
Patient Name: test1
Patient Priority: 1
Patient Name: test2
Patient Priority: 2
Patient Name: quit
Patient name: test1 Priority: 1
Patient name: test2 Priority: 2
As you can see, the list items are entered and then upon entering 'quit' the code prints the list contents.
The problem i have is that upon entering 'quit' and printing the list items, when i enter back into the program the items have gone.
What i am trying to achieve is running the gatherInfo function, then printing the list (in its entirety) and then going back to the gatherInfo function to add another item. For example, my output may be like:
Patient Name: test1
Patient Priority: 1
Patient name: test1 Priority: 1
Patient Name: test2
Patient Priority: 2
Patient name: test1 Priority: 1
Patient name: test2 Priority: 2
Patient Name: quit (Quit program, doesn't matter what happens now)
I have made several attempts at implementing this; for example, calling my printDetails function during each gatherInfo loop to print 'info', but with little success. How can i implement this into my design?
I suggest you do this:
Modify your gather info function so it takes info of only one patient.
Then create another function, let's call it main':
main' patients = do patient <- gatherInfo
if (fst patient == "quit")
then return ()
else do
let patients' = patient:patients -- add patient to list of patients
putStrLn . unlines . map printDetails $ patients' -- print list of patients
main' patients' -- continue
What are we doing here is remembering state of your program by passing parameter (this is how it is done in Haskell, as you have no states).
Now your main function would look like this:
main = main' [] -- start with empty list of patients
You may notice that I presumed your function gatherInfo will return patient with name "quit" when user inputs "quit", however you can do that some other way

Haskell Last generator in do {...} must be an expression error typed binding error

Im doing a small system from Haskell and im getting two errors called
"Last generator in do {...} must be an expression" and
"Type error in explicitly typed binding
Term : (fname,lname,cnic)
Type : (a,b,c)
Does not match : Database"
im new to haskell so plz help me out.
-------Data types-------
type FirstName = String
type LastName = String
type CustomerNIC = String
type Database = ( FirstName , LastName , CustomerNIC )
--type Details = [Database]
------Data base---------
exampleBase :: [Database]
exampleBase = [ ( "Kevin" , "Desilva" , "8929323V" ),( "Nimal" , "Perera" , "89120323V" ) ]
-------Main Menu-----------------------------
getInt :: IO Int
getInt = do line <- getline
return (read line :: Int)
selectsearch ::IO()
selectsearch = do
putStr"\n\n\t 1.Search by NIC:"
putStr"\n\n\t 2.Search by First Name:"
putStr"\n\n\t Your Chocie:"
input<-getInt
subsearch input
subsearch :: Int->IO()
subsearch x = do
if(x=1) then do
putStr"\n\t Enter NIC:"
cnic <- getLine
subsearch
else if (x=2) then do
putStr"\n\t Enter First Name:"
cnic <- getLine
subsearch
else if (x=3) then putStr "\n ERROR"
selectsearch
else MainMenu
------- Search ------------
getfName :: Database -> FirstName
getfName ( fname , lname , cnic ) = fname
searchByFirstName :: Database -> FirstName -> Database
searchByFirstName (a:ax) fname
| fname == getfName a = a
| length ax == 0 && getfName a/= fname = ("No Data","",0)
| otherwise = searchByFirstName ax fname
A few points:
There are weird indentation things throughout. Make sure you're using spaces and not tabs.
In subsearch, you often have cnic <- getLine (when you probably want getInt), but then not use that in the recursive call.
In your if statements, you should have x == 1, etc. rather than x = 1. Also consider using a case statement or guards rather than nested if-then-else.
You're missing a "do" in your x == 3 case.
getInt is identical to readLn.
Your searchByFirstName function could be written better.
A Database is made of three String fields, but your error case in searchByFirstName returns a value of type (String, String, Int).

Resources