Skip to content

Commit 93672c2

Browse files
committed
First few Haskell source code files.
1 parent ab99757 commit 93672c2

File tree

4 files changed

+147
-0
lines changed

4 files changed

+147
-0
lines changed

factorial.hs

+6
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
-- simple factorial definition
2+
3+
fact2 :: Int -> Int
4+
--fact2 n = if n==0 then 1 else n*fact2(n-1)
5+
fact2 0 = 1
6+
fact2 n = n*fact2(n-1)

nobles.hs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
-- make people noble
2+
3+
mknoble :: Bool -> String -> String
4+
mknoble female name = (if female then "Dame " else "Sir ")
5+
++ name

starman.hs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#!/usr/bin/env runhaskell
2+
-- starman
3+
-- Guessing Game
4+
-- https://www.futurelearn.com/courses/functional-programming-haskell/5/steps/505463
5+
------------------------------------------------------------------------------------
6+
---- work out the type of a function first ----
7+
-- The secret word, a String
8+
-- The current display, also a String
9+
-- The character guessed by the player
10+
check :: String -> String -> Char -> (Bool,String)
11+
check word display c
12+
= (c `elem` word, [if x==c
13+
then c
14+
else y | (x,y) <- zip word display])
15+
16+
---- we need to check how many guesses the player has left:
17+
--if n == 0
18+
---- If there are any guesses left, then we need to see whether the player is correct or not:
19+
--if word == display
20+
21+
turn :: String -> String -> Int -> IO ()
22+
turn word display n =
23+
do if n==0
24+
then putStrLn "You lose"
25+
else if word==display
26+
then putStrLn "You win!"
27+
else mkguess word display n
28+
29+
mkguess :: String -> String -> Int -> IO () -- my guess was String for IO () -- rs 2019-05-08
30+
------------------------
31+
--mkguess word display n =
32+
-- do putStrLn (display ++ " " ++ take n (repeat '*'))
33+
-- putStr " Enter your guess: "
34+
-- q <- getLine
35+
-- let (correct, display') = check word display (q!!0)
36+
-- let n' = if correct then n else n-1
37+
-- turn word display' n'
38+
------------------------
39+
mkguess word display n =
40+
do putStrLn (display ++ " " ++ take n (repeat '*'))
41+
putStr " Enter your guess: "
42+
q <- getLine
43+
let (correct, display') = check word display (q!!0)
44+
let n' = if correct then n else n-1
45+
turn word display' n'
46+
47+
48+
-- top-level function
49+
starman :: String -> Int -> IO ()
50+
starman word n = turn word ['-' | x <- word] n
51+
52+

starman.lhs

+84
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,84 @@
1+
#!/usr/bin/env runhaskell
2+
3+
-- starman
4+
-- Guessing Game
5+
-- https://www.futurelearn.com/courses/functional-programming-haskell/5/steps/505463
6+
------------------------------------------------------------------------------------
7+
Guessing Game
8+
9+
Now lets put together everything we have learned this week. We are going to write a moderately long Haskell program, consisting of multiple functions and I/O actions.
10+
Guessing Game
11+
12+
The program is going to be a guessing game, called Starman. In this single-player, text-based game, there is a word which the player needs to guess. For each turn of the game, the player guesses a single letter. If that letter is correct, then the guessed letters are displayed in the correct places in the word. If that letter is incorrect, then the user loses a star. Once the user has no stars left, they have lost the game. However if the user guesses all the letters in the word, they have won the game.
13+
14+
Because this game is quite long, we should use a texteditor (like Notepad++ on Windows, TextEdit on Mac or Gedit on Linux). Well, I actually use emacs if youve heard of it. Start by creating an empty text file called starman.hs the hs extension is to indicate that this file contains Haskell source code.
15+
Key Functions
16+
17+
The heart of the game involves checking the players guess. We want to know whether the guess was right. This outcome is a Bool value, either True or False. We need to update the displayed word, if the guess was right, by replacing appropriate dashes in the displayed word with the correctly guessed character. Therefore the result type of the function is a pair (Bool, String). The first element of the pair is the guess outcome. The second element is the String to display to the user for the next round.
18+
19+
Now, the checking function needs to know:
20+
21+
The secret word, a String
22+
The current display, also a String
23+
The character guessed by the player
24+
25+
These are the inputs to the checking function. So now we can state the type of the function:
26+
27+
check :: String -> String -> Char -> (Bool,String)
28+
29+
Here is a great programming tip. Its always helpful to work out the type of a function first. This focuses your attention on what the function is supposed to compute, and what data it needs to do it. Good software engineers do specification before implementation.
30+
31+
What will the check function body look like? The players guess is correct if and only if the guessed character c is in the target word. So the guess is correct if
32+
33+
c `elem` word
34+
35+
The new displayed word will be:
36+
37+
[(if x==c then c else y) | (x,y) <- zip word display]
38+
39+
This is a list comprehension, where we select each letter from either the actual word or the old display. The word is plaintext, whereas the display starts with all dashed characters.
40+
41+
> check :: String -> String -> Char -> (Bool, String)
42+
> check word display c
43+
> = (c `elem` word, [if x==c
44+
> then c
45+
> else y | (x,y) <- zip word display])
46+
47+
The next function we will define is the turn function. This is the function that will be called each time it is the players turn to enter a guess. First we need to check how many guesses the player has left:
48+
49+
if n == 0
50+
51+
If there are any guesses left, then we need to see whether the player is correct or not:
52+
53+
if word == display
54+
55+
So we will have two if checks, each followed by putStrLn status messages and the end of the function calling sequence (since it is the end of the game). However if neither of the if conditions is true, then the player can take a turn, so we call another function to get another character from the user input.
56+
57+
> turn :: String -> String -> Int -> IO ()
58+
> turn word display n =
59+
> do if n==0
60+
> then putStrLn "You lose"
61+
> else if word==display
62+
> then putStrLn "You win!"
63+
> else mkguess word display n
64+
65+
Note that there is a neater way to write the turn function, using Haskell guards, but we wont learn about guards until next week.
66+
67+
mkguess :: String -> String -> Int -> IO () -- define data types
68+
69+
> mkguess word display n =
70+
> do putStrLn (display ++ " " ++ take n (repeat '*'))
71+
> putStr " Enter your guess: "
72+
> q <- getLine
73+
> let (correct, display') = check word display (q!!0)
74+
> let n' = if correct then n else n-1
75+
> turn word display' n'
76+
77+
What is the type of mkguess? Can you work it out and add it before the function definition? We grab a line of user input, but only use the first character for the guess. This will fail if the user just hits ENTER without typing any characters, since q will be an empty string.
78+
79+
OK, so now we just need a top-level function. Lets call this starman:
80+
81+
> starman :: String -> Int -> IO ()
82+
> starman word n = turn word ['-' | x <- word] n
83+
84+
This function takes two arguments, the first is the word to be guessed, and the second is the number of incorrect guesses the player is allowed.

0 commit comments

Comments
 (0)