diff --git a/3_Intermediate.org b/3_Intermediate.org index bef07bc..a90095b 100644 --- a/3_Intermediate.org +++ b/3_Intermediate.org @@ -550,10 +550,50 @@ guessNum nbTry nbToFound = do guessNum (nbTry + 1) nbToFound #+END_SRC -#+BEGIN_COMMENT -****** TODO Let's explain each line of the that function. -#+END_COMMENT +Let's read the program line by line: +- ~putText "What is your guess?"~ should be straightforward. +- ~answer <- getLine~ So the ~getLine~ read from standard input and returns the + line entered by the user. The line will be put in the ~answer~ variable. +- ~let guessedNumber = readMaybe (toS answer)~: there are a few things to tell about this line. + +If you open GHCI and ask the type for each interresting symbol here is what you get: + +#+BEGIN_SRC +λ :t getLine +getLine :: IO Text + +λ :t toS +toS :: StringConv a b => a -> b + +λ :t readMaybe +readMaybe :: Read a => GHC.Base.String -> Maybe a +#+END_SRC + + - ~answer~ comes from ~getLine :: IO Text~ so ~answer~ should have the type ~Text~. + - Now we want to read this ~Text~ and see if this is a number and compare it to another ~Int~. + - To transform the number we don't use a function ~textToInt~ we simply use a + quite generic function ~readMaybe~ that take some ~String~ and try to + transform that to some type. For our specific case, the compiler is able to + figure out the type we want to transform the text into is ~Int~. Take the + time to digest that: ~Int~ is specified in the type signature of the + ~guessNum~ function so the compiler could discover that ~readMaybe~ should + return a ~Maybe Int~. How does he do that? Let's follow: + 1. see a ~n == nbToFound~ so we can deduce ~n~ and ~nbToFound~ have the same type. + 2. Reading the type signature of the function it is clear ~nbToFound~ is of + type ~Int~ (it's the second argument of a function with type ~Int -> Int -> IO ()~) + 3. Then ~n~ is generated from a pattern matching; the case ~Just n~ which + could be the the result of the ~readMaybe~ function. So we can deduce + that the ~a~ in the type signature of ~readMaybe~ is ~Int~ for this specific case. + - so ~guessedNumber :: Maybe Int~, if the user enter something that cannot be + transformed in number from a string then ~guessedNumber~ would be equal + to ~Nothing~ and we ask the user to enter a number. If the user entered a + number the type will be ~Just n~ were ~n~ will be an ~Int~. + - We compare the ~guessedNumber~ to the number to found ~nbToFound~. + - If the user found the right number we stop here by displaying the number of try. + - If the user hasn't found the number, depending on its value we tell the user + it's either too low or too high and we call the same function, this time, we + increment the number of try. The full program is then: @@ -718,6 +758,28 @@ to use a library to parse options. For that we will use the =optparse-generic= package. + +#+BEGIN_SRC haskell :tangle code/optparse_1.hs +#!/usr/bin/env stack +{- stack script + --resolver lts-11.6 + --install-ghc + --package protolude + --package optparse-generic +-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +import Protolude +import System.Environment (getArgs) + +main :: IO () +main = do + arguments <- getArgs + case head arguments of + Just filename -> die ("The first argument is: " <> toS filename) + Nothing -> die "Please enter a filename" +#+END_SRC + *** TODO File Access *** TODO Daemons & Logging ** TODO Intermediate diff --git a/code/optparse_1.hs b/code/optparse_1.hs new file mode 100755 index 0000000..b5ce369 --- /dev/null +++ b/code/optparse_1.hs @@ -0,0 +1,18 @@ +#!/usr/bin/env stack +{- stack script + --resolver lts-11.6 + --install-ghc + --package protolude + --package optparse-generic +-} +{-# LANGUAGE NoImplicitPrelude #-} +{-# LANGUAGE OverloadedStrings #-} +import Protolude +import System.Environment (getArgs) + +main :: IO () +main = do + arguments <- getArgs + case head arguments of + Just filename -> die ("The first argument is: " <> toS filename) + Nothing -> die "Please enter a filename"