Learn you more Haskell
It’s time for some more Haskell. I’m going to work through chapter 2 of Exercises for Programmers: 57 Challenges to Develop Your Coding Skills and see what happens.
Saying Hello
Create a program that prompts for your name and prints a greeting using your name.
Constraints: Keep the input, string concatenation, and output separate.
import System.IO
main = do
hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
putStr ("What is your name? ")
name <- getLine
let greeting = "Hello, " ++ name ++ ", nice to meet you!"
putStrLn (greeting)
Well, that was simpler than my first program and there’s nothing new to mention so I’ll move straight on to the first challenge.
Write a new version of the program without using any variables
import System.IO
greet :: String -> String
greet name = "Hello, " ++ name ++ ", nice to meet you!"
main = do
hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
putStr "What is your name? "
name <- getLine
putStrLn (greet name)
I thought about this for a while and I would like to solve it by writing functions and combining them. I can write a function greet
to concatenate the name and greeting but I’m not sure how to write the function that prints the question and returns the name that the user enters as a String
instead of an IO String
, so I’m still using one variable that binds to the value that GetLine
produces. I’ll come back to this once I learn some more about monads.
Write a version of the program that displays different greetings for different people.
import System.IO
greet :: String -> String
greet "Bob" = "Hello, Bob, great to see you!"
greet "Alice" = "Hello, Alice, it's been too long!"
greet name = "Hello, " ++ name ++ ", nice to meet you!"
main = do
hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
putStr "What is your name? "
name <- getLine
putStrLn (greet name)
I extended the greet
function to greet Bob and Alice differently by using pattern matching on the input parameter.
Let’s move onto to the next part of the chapter.
Counting the Number of Characters
Create a program that prompts for an input string and displays output that shows the input string and the number of characters the string contains.
Constraints: Be sure the output contains the original string. Use a single output statement to construct the output. Use a built-in function of the programming language to determine the length of the string.
import System.IO
main = do
hSetBuffering stdout NoBuffering
hSetBuffering stdin NoBuffering
putStr "What is the input string? "
input <- getLine
putStrLn (input ++ " has " ++ show (length input) ++ " characters")
I use the built in length
function to calculate the length of the input and because it’s an Integer
I use show
to get its String
representation.
If the user enters nothing, state that the user must enter something into the program
import System.IO
prompt :: IO ()
prompt = do
putStr "What is the input string? "
hFlush stdout
str <- getLine
if length str > 0
then putStrLn (str ++ " has " ++ show (length str) ++ " characters")
else prompt
main = do
prompt
Here I made a function called prompt
that asks the user to input a string. If the length of the string is greater than 0 then I print the output, otherwise I recursively call prompt
again to ask the user for input. I also saw how to use hFlush stdout
when I need to flush the output which is much nicer than the hSetBuffering stdout NoBuffering
and hSetBuffering stdin NoBuffering
I was doing before.
There is a third challenge to implement the program with a GUI, but I’m going to leave that for now until I learn some more Haskell!
Printing Quotes
Create a program that promts for a quote and an author. Display the quotation and author in the specified format.
Constraints: Use a single output statement to produce this output. Use string concatenation (not templates).
import System.IO
main = do
putStr "What is the quote? "
hFlush stdout
quote <- getLine
putStr "Who said it? "
hFlush stdout
author <- getLine
putStrLn (author ++ " says, \"" ++ quote ++ "\"")
This is very similar to the other programs. I had to escape the double quotes with a \
.
Modify this program so that instead of prompting for quotes from the user, you create a structure that holds quotes and their associated attributions and then display all of the quotes using the specified format.
import System.IO
quotes :: [(String, String)]
quotes =
[("Obi Wan Kenobi", "These aren't the droids you're looking for."),
("Neil Armstrong", "Houston, Tranquility Base here. The Eagle has landed."),
("Arnold Schwarzenegger", "I'll be back!")]
printQuote :: (String, String) -> IO ()
printQuote (author, quote) = putStrLn (author ++ " says, \"" ++ quote ++ "\"")
main = do
mapM_ printQuote quotes
This was an interesting modification. First I stored the quotes as a list of tuples with two String
elements. Then I found the mapM_
function that takes a data structure and a monadic action and applies the action to each element. I wrote a little function called printQuote
to take an (author, quote) tuple and print it with some formatting. Then in main
I call mapM_
with two arguments, my printing function and the list of quotes, and behold, the quotes are printed.
I feel like I’ve gone a little too far without learning some more fundamentals at this stage, but the chapter is almost over, only one more program to write.
Mad Lib
Create a simple mad-lib program that prompts for a noun, a verb, an adverb, and an adjective and injects those into a story that you create.
Constraints: Use a single output statement for this program. If your language supports string interpolation or string substitution, use it to build up the output
import System.IO
import Text.Printf
main = do
putStr "Enter a noun: "
hFlush stdout
noun <- getLine
putStr "Enter a verb: "
hFlush stdout
verb <- getLine
putStr "Enter an adjective: "
hFlush stdout
adjective <- getLine
putStr "Enter an adverb: "
hFlush stdout
adverb <- getLine
let madlib = "If you %s your %s %s %s I will eat my hat!"
printf madlib verb adjective noun adverb
I found a printf
function to do the string interpolation.
There’s a challenge to add more inputs to the program to expand the story but I’m going to stop here and move on to the next chapter to work on some numeric problems and learn some more tricks before I try to write a larger program.