Last active
December 20, 2015 06:29
-
-
Save cleichner/6086604 to your computer and use it in GitHub Desktop.
I re-wrote a toy Java program in Haskell and messed with the style ... a lot.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| // Java code that started it all | |
| import java.util.Random; | |
| import java.util.Scanner; | |
| public class RandomProblem { | |
| public static void main(String[] args) { | |
| int right = 0; | |
| int rounds = 0; | |
| Scanner keyboard = new Scanner(System.in); | |
| Random rand = new Random(); | |
| while (keepPlaying(keyboard)) { | |
| int x = rand.nextInt(100) + 1; | |
| int y = rand.nextInt(100) + 1; | |
| int solution = 0; | |
| if (rand.nextBoolean()) { | |
| solution = x + y; | |
| printQuestion(x, '+', y); | |
| } else { | |
| solution = x - y; | |
| printQuestion(x, '-', y); | |
| } | |
| rounds++; | |
| if (solution == keyboard.nextInt()) { | |
| System.out.println("Correct!"); | |
| right++; | |
| } else { | |
| System.out.println("Sorry! the correct answer is: " + solution); | |
| } | |
| System.out.println("You have solved " + right + " out of " + | |
| rounds + " problems correctly."); | |
| } | |
| } | |
| public static boolean keepPlaying(Scanner keyboard) { | |
| System.out.print("Would you like to play? y/n: "); | |
| return keyboard.next().toLowerCase().equals("y"); | |
| } | |
| public static void printQuestion(int x, char op, int y) { | |
| System.out.print("What is " + x + " " + op + " " + y + "? "); | |
| } | |
| } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- First Haskell version, nothing tricky | |
| import Control.Monad | |
| import Data.Char | |
| import System.IO | |
| import System.Random | |
| gameLoop :: [Int] -> Int -> Int -> IO () | |
| gameLoop (x:y:values) right rounds = do | |
| flushPut "Would you like to play? y/n: " | |
| keepPlaying <- getLine | |
| when (map toLower keepPlaying == "y") $ do | |
| let (op, opStr) = [((+), "+") , ((-), "-")] !! (x `mod` 2) | |
| flushPut $ unwords [show x, opStr, show y, "= "] | |
| let solution = x `op` y | |
| response <- readLn | |
| let (total, message) = if solution == response | |
| then (right + 1, "Correct!") | |
| else (right, unwords ["Sorry! the correct answer is:", show solution]) | |
| putStr $ unwords | |
| [message, "\nYou have solved", show total, "out of", show (rounds + 1), "\n"] | |
| gameLoop values total (rounds + 1) | |
| where | |
| flushPut s = putStr s >> hFlush stdout | |
| main :: IO () | |
| main = do | |
| gen <- getStdGen | |
| gameLoop (randomRs (1, 100) gen) 0 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Introduced applicative and pointfree style | |
| import Control.Applicative | |
| import Control.Monad | |
| import Data.Char | |
| import System.IO | |
| import System.Random | |
| gameLoop :: [Int] -> Int -> Int -> IO () | |
| gameLoop (x:y:values) right rounds = do | |
| flushPut "Would you like to play? y/n: " | |
| keepPlaying <- ("y" ==) . map toLower <$> getLine | |
| when keepPlaying $ do | |
| let (op, opStr) = [((+), "+") , ((-), "-")] !! (x `mod` 2) | |
| flushPut $ unwords [show x, opStr, show y, "= "] | |
| let solution = x `op` y | |
| correct <- readLn | |
| let (total, message) = if solution == response | |
| then (right + 1, "Correct!") | |
| else (right, unwords ["Sorry! the correct answer is:", show solution]) | |
| putStr $ unwords | |
| [message, "\nYou have solved", show total, "out of", show (rounds + 1), "\n"] | |
| gameLoop values total (rounds + 1) | |
| where flushPut = (>> hFlush stdout) . putStr | |
| main :: IO () | |
| main = do | |
| gen <- getStdGen | |
| gameLoop (randomRs (1,100) gen) 0 0 |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Made state-passing explicit with StateT and record | |
| import Control.Applicative | |
| import Control.Monad | |
| import Control.Monad.State | |
| import Data.Char | |
| import System.IO | |
| import System.Random | |
| data Game = Game { values :: [Int], right :: Int, rounds :: Int } | |
| updateGame :: Bool -> Game -> Game | |
| updateGame correct Game { values = (_:_:remaining) | |
| , right = score | |
| , rounds = total } = | |
| Game { values = remaining | |
| , right = if correct then score + 1 else score | |
| , rounds = total + 1 } | |
| gameLoop :: StateT Game IO () | |
| gameLoop = do | |
| flushPut "Would you like to play? y/n: " | |
| keepPlaying <- ("y" ==) . map toLower <$> liftIO getLine | |
| when keepPlaying $ do | |
| (x:y:_) <- gets values | |
| let (op, opStr) = [((+), "+") , ((-), "-")] !! (x `mod` 2) | |
| flushPut $ unwords [show x, opStr, show y, "= "] | |
| let solution = x `op` y | |
| response <- liftIO readLn | |
| game <- modify (updateGame correct) >> get | |
| liftIO . putStrLn $ if solution == response | |
| then "Correct!" | |
| else unwords ["Sorry! the correct answer is:", show solution] | |
| liftIO . putStr $ unwords | |
| ["You have solved", show $ right game, "out of", show $ rounds game, "\n"] | |
| gameLoop | |
| where | |
| flushPut = liftIO . (>> hFlush stdout) . putStr | |
| main :: IO () | |
| main = do | |
| randomValues <- randomRs (1,100) <$> getStdGen | |
| evalStateT gameLoop Game { values = randomValues, right = 0, rounds = 0 } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Factored message into a function | |
| import Control.Applicative | |
| import Control.Monad | |
| import Control.Monad.State | |
| import Data.Char | |
| import System.IO | |
| import System.Random | |
| data Game = Game { values :: [Int], right :: Int, rounds :: Int } | |
| updateGame :: Bool -> Game -> Game | |
| updateGame correct Game { values = (_:_:remaining) | |
| , right = score | |
| , rounds = total } = | |
| Game { values = remaining | |
| , right = if correct then score + 1 else score | |
| , rounds = total + 1 } | |
| gameLoop :: StateT Game IO () | |
| gameLoop = do | |
| flushPut "Would you like to play? y/n: " | |
| keepPlaying <- ("y" ==) . map toLower <$> liftIO getLine | |
| when keepPlaying $ do | |
| (x:y:_) <- gets values | |
| let (op, opStr) = [((+),"+"), ((-),"-")] !! (x `mod` 2) | |
| flushPut $ unwords [show x, opStr, show y, "= "] | |
| let solution = x `op` y | |
| correct <- (solution ==) <$> liftIO readLn | |
| game <- modify (updateGame correct) >> get | |
| liftIO . putStr $ unwords [message solution correct, | |
| "\nYou have solved", show $ right game, "out of", show $ rounds game, "\n"] | |
| gameLoop | |
| where | |
| flushPut = liftIO . (>> hFlush stdout) . putStr | |
| message _ True = "Correct" | |
| message solution _ = unwords ["Sorry! the correct answer is:", show solution] | |
| main :: IO () | |
| main = do | |
| randomValues <- randomRs (1,100) <$> getStdGen | |
| evalStateT gameLoop Game { values = randomValues, right = 0, rounds = 0 } |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -- Went golfing. Applied all of the above refactorings, but only to shrink code. | |
| import Control.Applicative | |
| import Control.Monad | |
| import Data.Char | |
| import System.IO | |
| import System.Random | |
| main :: IO () | |
| main = getStdGen >>= gameLoop 0 0 . randomRs (1, 100) where | |
| gameLoop right rounds (x:y:values) = do | |
| putStr "Would you like to play? y/n: " >> hFlush stdout | |
| ("y" ==) . map toLower <$> getLine >>= flip when (do | |
| let (op, opStr) = [((+), "+") , ((-), "-")] !! (x `mod` 2) | |
| putStr (unwords [show x, opStr, show y, "= "]) >> hFlush stdout | |
| (total, message) <- ap ((.) . updateGame right) (==) (x `op` y) <$> readLn | |
| putStr $ unwords [message, "\nYou have solved", show total, "out of", show (rounds + 1), "\n"] | |
| gameLoop total (rounds + 1) values) | |
| updateGame total _ True = (total + 1, "Correct") | |
| updateGame total solution _ = (total, unwords ["Sorry! the correct answer is:", show solution]) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment