I am new to Haskell, and I want to make a program with lists. I want to read from keyboard next element, and append everything to my existing list. Because I used data types, I don't know how to add a new car with all those details, in my list named cars.
I know that sequence let ls = name:model:color:year:price:coin:[cars] is wrong and I have no ideea how to make it work. Can anyone give me an ideea about what can I do here please?
type Name = String
type Model = String
type Color= String
type Year = String
type Price = String
type Coin = String
data Car = Car String String String String String String deriving (Show)
cars :: [Car]
cars = [Car "Range Rover" "Sport Supercharged" "Blue" "2015" "85790" "$" , Car "BMW" "4-Series" "Black" "2014" "65489" "$"]
main = do
putStrLn "Car details "
putStr "Name: "
name <- getLine
putStr "Model: "
model <- getLine
putStr "Color: "
color <- getLine
putStr "Year: "
year <- getLine
putStr "Price: "
price <- getLine
putStr "Coin: "
coin <- getLine
let ls = name:model:color:year:price:coin:[cars]
putStrLn (show ls)
First I'd recommend you actually use those type synonyms, if you define them at all:
data Car = Car Name Model Color Year Price Coin
deriving (Show)
Note that this is completely equivalent to declaring all fields String (because Model and String are just different names for exactly the same type), it's just clearer to read. Even clearer might be if you used record fields for such a type, but that wouldn't make a difference here.
Now to “create” a new car from some string properties, you want to not concatenate these properties to a list. Instead, just use the Car constructor and prepend a single car to the list.
main = do
putStrLn "Car details "
putStr "Name: "
name <- getLine
...
let cars' = Car name model color year price coin : cars
print cars'
In case you wonder: Car foo bar baz : cars is the same as (Car foo bar baz) : (cars). In fact, Car is just used like any other function here; you could also define a helper function
redCar :: Name -> Model -> Year -> Price -> Coin -> Car
redCar n m y p c = Car n m "red" y p c
and then write
print $ redCar name model year price coin : cars
OTOH, [cars] is not a list of cars that you could prepend another car to; rather it's a list with a single element (and that element is a list of cars).
A different subject is how you update stuff in general, in Haskell. ErikR adresses how this can be done with recursion; I'd note that you can also have proper mutable variables in Haskell IO code. We generally avoid working in IO as much as possible, but if you actually write an interactive application then it's sensible enough:
import Data.IORef
main = do
knownCars <- newIORef cars
putStrLn "Car details "
...
modifyIORef knownCars $ Car name model color year price coin
print =<< readIORef cars
Then you can follow this with
putStrLn "Details of another car:"
...
modifyIORef knownCars $ Car name2 model2 color2 year2 price2 coin2
and actually have both cars added. Of course this only makes sense if the whole program is actually running in a loop. (“Loop” still meaning recursion, in fact.)
As you probably have been told, Haskell "variables" are not mutable. That means you have to explicitly pass state around as a parameter in your loop.
For example, this is a loop which will repeatedly ask the user for a color:
loop1 = do putStrLn "Enter a color: "
color <- getLine
loop1
However, the users's input is not "saved" anywhere. The next step is to keep track of all of previous input as a parameter to the looping function:
loop2 colors = do putStrLn $ "Previous colors: " ++ show colors
putStrLn "Enter a color: "
color <- getLine
loop2 (color:colors)
Hopefully this helps.
Related
I'm trying to make sense of one of the examples presented at the pipes tutorial concerning ListT:
import Pipes
import qualified Pipes.Prelude as P
input :: Producer String IO ()
input = P.stdinLn >-> P.takeWhile (/= "quit")
name :: ListT IO String
name = do
firstName <- Select input
lastName <- Select input
return (firstName ++ " " ++ lastName)
If the example above is run, we get output like the following:
>>> runEffect $ every name >-> P.stdoutLn
Daniel<Enter>
Fischer<Enter>
Daniel Fischer
Wagner<Enter>
Daniel Wagner
quit<Enter>
Donald<Enter>
Stewart<Enter>
Donald Stewart
Duck<Enter>
Donald Duck
quit<Enter>
quit<Enter>
>>>
It seems that:
When you run this (on ghci), the first name you input will get bound and only the second will change. I would expect that both producers (defined by Select input) will take turns (maybe non-deterministically) at reading the input.
Entering quit one time will allow to re-bind the first name. Again, I fail to see why firstName will get bound to the first value entered by the user.
Entering quit twice in a row will terminate the program. However, I would expect that quit only has to be entered twice to quit the program (possibly alternating with other input).
I'm missing something fundamental about the way the example above works, but I cannot see what.
When you run this (on GHCi), the first name you input will get bound
and only the second will change. I would expect that both producers
(defined by Select input) will take turns (maybe
non-deterministically) at reading the input.
ListT doesn't work that way. Instead, it is "depth-first". Every time it gets a first name, it starts reading the whole list of last names anew.
The example doesn't do that, but each list of last names could depend on the first name that has been read previously. Like this:
input' :: String -> Producer String IO ()
input' msg =
(forever $ do
liftIO $ putStr msg
r <- liftIO $ getLine
yield r
) >-> P.takeWhile (/= "quit")
name' :: ListT IO String
name' = do
firstName <- Select input
lastName <- Select $ input' $ "Enter a last name for " ++ firstName ++ ": "
return (firstName ++ " " ++ lastName)
Entering quit one time will allow to re-bind the first name. Again, I
fail to see why firstName will get bound to the first value entered by
the user.
If we are reading last names and encounter a quit command, that "branch" terminates and we go back to the level above, to read another first name from the list. The "effectful list" that reads the last names is only re-created after we have a first name to work with.
Entering quit twice in a row will terminate the program. However, I
would expect that quit only has to be entered twice to quit the
program (possibly alternating with other input).
Notice that entering a single quit at the very beginning will also terminate the program, as we are "closing" the top-level list of first names.
Basically, every time you enter a quit you close the current branch and go up a level in the "search tree". Every time you enter a first name you go down one level.
To add to #danidiaz's great answer, you can get the behavior of name prompting for a firstName again, instead of just keep asking for lastNames.
What you can do is make use of the MonadZip instance of Monad m => ListT m, particularly
mzip :: Monad m => ListT m a -> ListT m b -> ListT m (a, b).
Thus, you could define name as
name :: ListT IO String
name = do
(firstName, lastName) <- mzip (Select input) (Select input)
return (firstName ++ " " ++ lastName)
and you get your alternating behavior.
As a nice aside, you can use the MonadComprehensions and ParallelListComp extensions as well. Using these, the two versions of name become
name :: ListT IO String
name = [ firstName ++ " " ++ lastName | firstName <- Select input
, lastName <- Select input ]
name' :: ListT IO String
name' = [ firstName ++ " " ++ lastName | firstName <- Select input
| lastName <- Select input ]
I'm trying to build a string from optional arguments. For example to generate a greeting string from a title and a name This is trivial in a imperative language and would look like this
def greeting(title, name):
s = "Hello"
if a :
s += "Mr"
if b:
s += b
My first attempt in haskell is :
greeting :: Bool-> Maybe String -> String
greeting title name = foldl (++) "Hello" (catMaybes [title' title, name])
where
title' True = Just "Mr"
title' False = Nothing
I'm sure there is a bette way to do it. First, I'm sure this foldl catMaybes combination exists somewhere but I couldn't find it. Second, folding works here because I'm using the same operation (and the same type). So what is there a better way to do it ?
I was also thinking using a Writer but I'm not sure either how to do it.
Update
This is only an example (maybe bad or too simple). My question is more , how to generalize it to many arguments .
So the real problem is not just about concatening 2 strings but more how to generate letters from a template with optional sections and parameters, like you would do in Word with the mail merge tool.
You have on one a csv file with customer name, telephone number, how much is overdue etc. Some of the field could be optional. On the other side you have a template and the goal is to generate one letter per customer (row) according to the *template. The question is then how do you write this template in haskell (without the help of any templating library).
In my first example the template will be "hello (Mr){name}" but in the real word the template could be in invoice, a statement letter or even a complete accounting report.
Actually Haskell is smarter than any imperative approach.
Let's imagine name has a value Nothing. Does it make sense to render something like "Hello Mr"? Probably it would make more sense to consider it as an exceptional situation, and for that we can again use Maybe. So first of all, I'd update the signature of the function to the following:
greeting :: Bool -> Maybe String -> Maybe String
Now we can look at our problem again and find out that Haskell provides multiple ways to approach it.
Hello, Monads
Maybe is a monad, so we can use the do syntax with it:
greeting mr name = do
nameValue <- name
return $ if mr
then "Hello, Mr. " ++ nameValue
else "Hello, " ++ nameValue
Hello, Functors
Maybe is also a functor, so alternatively we can use fmap:
greeting mr name =
if mr
then fmap ("Hello, Mr. " ++) name
else fmap ("Hello, " ++) name
We can also do a bit of refactoring, if we consider the signature as the following:
greeting :: Bool -> (Maybe String -> Maybe String)
i.e., as a function of one argument, which returns another function. So the implementaion:
greeting mr =
if mr
then fmap ("Hello, Mr. " ++)
else fmap ("Hello, " ++)
or
greeting True = fmap ("Hello, Mr. " ++)
greeting False = fmap ("Hello " ++)
if you find this syntax better.
Haskell is so good at abstractions, it can easily replicate the imperative patterns. What you're doing in your example is called a "builder" pattern. Writer is a monad, which wraps a pattern of accumulation or "building" of any Monoid data, and String is a Monoid.
import Control.Monad.Writer hiding (forM_)
import Data.Foldable
greeting :: Bool -> Maybe String -> String -> String
greeting mr name surname =
execWriter $ do
tell $ "Hello,"
when mr $ tell $ " Mr."
forM_ name $ \s -> tell $ " " ++ s
tell $ " " ++ surname
tell $ "!"
main = do
putStrLn $ greeting False (Just "Ray") "Charles"
putStrLn $ greeting True Nothing "Bean"
Outputs:
Hello, Ray Charles!
Hello, Mr. Bean!
You could avoid using a Maybe for the title and do:
greeting :: Bool-> Maybe String -> String
greeting title name = "Hello" ++ title' ++ (maybe "" id name)
where title' = if title then "Mr" else ""
If you have a number of Maybes you could use mconcat since String is a monoid:
import Data.Monoid
import Data.Maybe
greeting :: [Maybe String] -> String
greeting l = fromJust $ mconcat ((Just "Hello"):l)
I think that your function is violating the SRP (Single responsibility principle). It is doing two things:
prefixing the name with Mr
rendering the greeting message
You can notice that the Bool and String (name) refer to the same "entity" (a person).
So let's define a person:
data Person
= Mister String
| Person String
deriving (Eq)
We can now create an instance of show that makes sense:
instance Show Person where
show (Mister name) = "Mr. " ++ name
show (Person name) = name
and finally we can reformulate your greeting function as:
greeting :: Maybe Person -> String
greeting (Just person) = "Hello, " ++ show person
greeting Nothing = "Hello"
Live demo
The code is simple, readable and just few lines longer (don't be afraid of writing code). The two actions (prefixing and greeting) are separated and everything is much simpler.
If you really have to, you can trivially create a function to generate a Mister or a Person based on a boolean value:
makePerson :: Bool -> String -> Person
makePerson True = Mister
makePerson False = Person
Live demo
I know it's an old post ... but it may be useful ...
in a pure "functional" way ...
greeting :: Maybe String -> String -> String
greeting Nothing name = "Hello" ++ ", " ++ name
greeting (Just title) name = "Hello" ++ ", " ++ title ++ " " ++ name ++ "!"
how to call :
-- greeting Nothing "John"
-- greeting Nothing "Charlotte"
-- greeting (Just "Mr.") "John"
-- greeting (Just "Miss.") "Charlotte"
///Edit
I have a problem with haskell. If someone can help me, that would be great.
I'm inserting records into a file using the following code:
check :: Int -> Int
check a
|a > 0 && a<=10 = a
|otherwise = error "oh. hmm.. enter a number from the given interval"
ame :: IO ()
ame = do
putStr "Enter the file name: "
name <- getLine
putStrLn "Do you want to add new records? "
question <- getLine
if question == "yes" then do
putStrLn "Enter your records:"
newRec <- getLine
appendFile name ('\n':newRec)
--new lines--
putStrLn "enter a number between 0 and 10: "
something <- getLine
return (read something:: Int)
let response = check something
putStrLn response
appendFile name ('\n':something)
putStrLn "enter something new again: "
something2 <- getLine
appendFile name ('\n':something2)
putStrLn "a"
else
putStr "b"
Now I want to extract some records from this file, using a specific criteria. For example, i want to extract and display records from even(or odd or any other criteria) rows. can I do that? if yes, how?
Also...
I want to check the user input. Let's say that I don't want him/her to enter a string instead of an integer. can I also check his/her input? do I need to create another function and call that function inside the code from above?
///Edit
thank you for answering. but how can i embed it into my previous code?
I've tried now to create a function(you can see the above code) and then call that function in my IO. but it doesn't work..
Yes, it is certainly possible to display only certain rows. If you want to base it off of the row number, the easiest way is to use zip and filter
type Record = String
onlyEven :: [Record] -> [Record]
onlyEven records =
map snd $ -- Drop the numbers and return the remaining records
filter (even . fst) $ -- Filter by where the number is even
zip [1..] -- All numbers
records -- Your records
This technique can be used in a lot of circumstances, you could even abstract it a bit to
filterByIdx :: Integral i => (i -> Bool) -> [a] -> [a]
filterByIdx condition xs = map snd $ filter (condition . fst) $ zip [1..] xs
-- Could also use 0-based of `zip [0..] xs`, up to you
onlyEven :: [a] -> [a]
onlyEven = filterByIdx even
If you want to check if an input is an Int, the easiest way is to use the Text.Read.readMaybe function:
import Text.Read (readMaybe)
promptUntilInt :: IO Int
promptUntilInt = do
putStr "Enter an integer: "
response <- getLine
case readMaybe response of
Just x -> return x
Nothing -> do
putStrLn "That wasn't an integer!"
promptUntilInt
This should give you an idea of how to use the function. Note that in some cases you'll have to specify the type signature manually as case (readMaybe response :: Maybe Int) of ..., but here it'll work fine because it can deduce the Int from promptUntilInt's type signature. If you get an error about how it couldn't figure out which instance for Read a to use, you need to manually specify the type.
You have
something <- getLine
return (read something:: Int)
let response = check something
putStrLn response
To step through what you're trying to do with these lines:
something <- getLine
getLine has the type IO String, meaning it performs an IO action and returns a String. You can extract that value in do notation as
something <- getLine
Just as you have above. Now something is a String that has whatever value was entered on that line. Next,
return (read something :: Int)
converts something to an Int, and then passes it to the function return. Remember, return is not special in Haskell, it's just a function that wraps a pure value in a monad. return 1 :: Maybe Int === Just 1, for example, or return 1 :: [Int] === [1]. It has contextual meaning, but it is no different from the function putStrLn. So that line just converts something to an Int, wraps it in the IO monad, then continues on to the next line without doing anything else:
let response = check something
This won't compile because check has the type Int -> Int, not String -> String. It doesn't make any sense to say "hello, world" > 0 && "hello, world" <= 10, how do you compare a String and an Int? Instead, you want to do
let response = check (read something)
But again, this is unsafe. Throwing an error on an invalid read or when read something is greater than 10 will crash your program completely, Haskell does errors differently than most languages. It's better to do something like
check :: Int -> Bool
check a = a > 0 && a <= 10
...
something <- getLine
case readMaybe something of
Nothing -> putStrLn "You didn't enter a number!"
Just a -> do
if check a
then putStrLn "You entered a valid number!"
else putStrLn "You didn't enter a valid number!"
putStrLn "This line executes next"
While this code is a bit more complex, it's also safe, it won't ever crash and it handles each case explicitly and appropriately. By the way, the use of error is usually considered bad, there are limited capabilities for Haskell to catch errors thrown by this function, but errors can be represented by data structures like Maybe and Either, which give us pure alternatives to unsafe and unpredictable exceptions.
Finally,
putStrLn response
If it was able to compile, then response would have the type Int, since that's what check returns. Then this line would have a type error because putStrLn, as the name might suggest, puts a string with a new line, it does not print Int values. For that, you can use print, which is defined as print x = putStrLn $ show x
Since this is somewhat more complex, I would make a smaller function to handle it and looping until a valid value is given, something like
prompt :: Read a => String -> String -> IO a
prompt msg failMsg = do
putStr msg
input <- getLine
case readMaybe input of
Nothing -> do
putStrLn failMsg
prompt
Just val -> return val
Then you can use it as
main = do
-- other stuff here
-- ...
-- ...
(anInt :: Int) <- prompt "Enter an integer: " "That wasn't an integer!"
-- use `anInt` now
if check anInt
then putStrLn $ "Your number multiplied by 10 is " ++ show (anInt * 10)
else putStrLn "The number must be between 1 and 10 inclusive"
You don't have to make it so generic, though. You could easily just hard code the messages and the return type like I did before with promptUntilInt.
I'm currently making a text based menu system in haskell. I have made a data type called Book where each function edits the list and returns it. However I cannot work out how to make a menu part work where it can edit this list and recurse back around.
Example on what I'm stuck on
menu works,
add a book to the list,
menu then needs to reload the menu so I can display the books with the new addition.
example of menu
menu:: [Book] -> [IO]
menu books = do
str <- getLine
let selectNum = (read str :: Int)
case selectNum of
1 -> let sd = addNewBookIO books
2 -> displayAllBooksFromYear books
example of adding a new book
addNewBookIO :: [Book] -> IO [Book]
addNewBookIO films =
do putStr "Film name: "
filmTitle <- getLine
putStr "List all cahr in the Book (separated by commas): "
cast <- addToStringArray []
putStr "Year of Realese in the UK: "
year <- getLine
let test = (read year :: Int)
putStr "List all the fans(separated by commas): "
fans <- addToStringArray []
putStrLn "Your Book has been added"
let bookList = addbookFilm (Film bookTitle cast test fans) films
return bookList
Any help would be grateful
At the moment your type signature for menu doesn't make any sense. Do you mean something like this?
menu :: [Book] -> IO [Book]
If so, then you could define it to be
menu books = do
str <- getLine
case read str of
1 -> do books' <- addNewBookIO books -- add a new book, then loop
menu books'
2 -> displayAllBooksFromYear books >> menu books -- display books, then loop
3 -> return books -- quit
This reads a string from the user, and then either adds a new book, displays the current list of books or ends the loop, returning the list of books.
Edit: The >> operator sequences two operations together. The combination a >> b means "do a, then do b".
The following two pieces of code are exactly equivalent (in fact, the first one is just syntactic sugar for the second)
do displayAllBooksFromYear books
menu books
and
displayAllBooksFromYear books >> menu books
Hope that helps clear things up.
I want the user to enter a list of tuples to search on it for a key like this can I say it like this
data BookInfo = Book Int String [String]
deriving(Show)
findbook :: [BookInfo] -> Int -> BookInfo
findbook vs key = (booker (vs!!(bookFinding vs key 0 (length vs))) key)
getBookInfo = do
putStrLn "Enter book id :"
k <- read
putStrLn "Enter book name : "
r <- getLine
putStrLn "Enter book subject :"
m <- getLine
let Book book = enter k r [m]
return book
main = do
putStr "Enter you first info is :"
v <- getBookInfo
let Book vs = v:[]
c <- getLine
if c == "N"
then
putStr "You done"
else
Book booke = getBookInfo
vs = booke:vs
putStr "Do you want to search ? :"
m <- getch
if m == 'y'
then
putStr " Enter your key :"
s <- readNum
let Book w = findBook vs s
putStrLn" The result is: " ++ show(w)
But it gives me an error:
The last statement in do must be m <- getch
What am I doing wrong?
It looks like you're trying to write a program to read a list of books into some sort of database, and then search the books. You start off well, with a data type that stores book info:
data BookInfo = Book Int String [String] deriving (Show)
Now let's look at your function which reads in book info from the user.
getBookInfo = do
putStrLn "Enter book id :"
k <- read
putStrLn "Enter book name : "
r <- getLine
putStrLn "Enter book subject :"
m <- getLine
let Book book = enter k r [m]
return book
I fixed up your indentation for you (here's a tip: use four spaces for indentation!) but there are other problems:
The line k <- read doesn't make any sense. The type of read is read :: Read a => String -> a but you're using it as if it was an I/O action. You need the function readLn instead.
The line let Book book = enter k r [m] doesn't make any sense. It looks like you're used to writing in a language like C or Java, where you have to specify types. You don't have to do that in Haskell! Also, the enter function is unnecessary. You can just write let book = Book k r [m] and that will work fine. In fact, you don't need the temporary variable book at all - you can create the Book and return it all in one line.
So you can write:
getBookInfo :: IO BookInfo
getBookInfo = do
putStrLn "Enter book id: "
bookid <- readLn
putStrLn "Enter book name: "
name <- getLine
putStrLn "Enter book subject: "
subject <- getLine
return (Book bookid name [subject])
which will now compile fine. Notice that I also added a type declaration (which is optional).
Your next function, main, is trying to do a bit too much. It contains all the rules for getting a list of books, and the rules for searching them. These are two separate tasks, so they should be in two separate functions. So let's write a function that gets a list of books:
getBookList :: IO [BookInfo]
getBookList = do
putStr "Any more books? "
answer <- getLine
if answer == "N"
then return []
else do
book <- getBookInfo
books <- getBookList
return (book:books)
Take a while to understand how this function works. First it asks if you have any more books to enter. If you say "N" then it returns the empty list, and you're done. Otherwise, it does something magical - first, it calls getBookInfo to get the info for a single book. Then it calls itself to get a list of books! This is an example of recursion. Finally, it adds the first book to the list of books, and returns the whole list.
You should have a go at writing the rest of the program yourself now. I may revisit this answer in a day or so to add some more detail. I'm more likely to do that if you leave a comment letting me know what you're tried, and where you get stuck. Remember:
Indent your code properly! Use four spaces. Get an editor like Sublime Text 2 that knows how to handle indentation.
Try and write small (less then 10 lines) functions and chain them together to make a complete program. This will prevent you from losing your mind when trying to debug the 400 line monstrosity you've come up with.
Check the types! You can load up ghci and type, for example, :t read to see the type of the read function.