While we can now createbasic.Target
andbasic.Guess
values and print theResultof their evaluation to the console, we're missing a key part of the Wordle experience! A user should not be able to guess a word that's shorter or longer than five characters, and the user should not be able to guess a nonsense word. If the user tries to do this, they should get a helpful message and have the opportunity to guess again.
Given the signature below, write the function,stubs.getUserInput
:
stubs.getUserInput : '{IO, Exception, Ask (Set Text)} stubs.Guess
It should do the following:
- Read the user input from the console
- Check its length
- Continue to prompt the user until the user enters a valid guess
readLine
readLine
We learned how to print a response to the console withIO
usingprintLine
—nowwe need togetthe user's response. The function for that isreadLine
from thebase
library.
readLine
is adelayed computation,so it won't try to read the user's input unless we call it with the!
operator. The!
operator is syntactic sugar for calling a function with no arguments,() -> a
.
Watch an example of running input and output in a loop:
Ask
abilityAsk
abilityIn the signature provided forstubs.getUserInput
,we're using theAsk
ability to represent the data we receive when we read the dictionary file into memory.Ask
has one request constructor,ask
which we can call when we need to inspect the dictionary data. Otherwise, theAsk
ability requirement can simply be passed through the function call chain.
Use theAsk
ability when you need to pass around data in an environment, but don't want to provide it explicitly as an argument to each upstream function.
Resources
Solutions
The implementation forbasic.getUserInput
is a series of if/else clauses. (Alternatively, you could use pattern matching.)
basic.getUserInput : '{IO, Exception, Ask (Set Text)} basic.Guess
basic.getUserInput : '{IO, Exception, Ask (Set Text)} basic.Guess
basic.getUserInput _ =
use Nat !=
use basic getUserInput
input = !readLine
normalized = Text.normalize input
if Text.size normalized != 5 then
printLine "🖐 guess must be a 5 letter word"
!getUserInput
else
use basic.Guess fromText
dict = ask
if Set.contains normalized dict then fromText normalized
else
acceptOverride = !(basic.overrideLookup normalized)
if acceptOverride then fromText normalized else !getUserInput
We have to call thereadLine
function with!
because it's a delayed computation and would otherwise never prompt the user for input. We then strip trailing whitespace and lowercase the input by default withText.normalize
.
The first condition that we check is the length of the user's input. If it's not5
,we start thebasic.getUserInput
function over again.
The second condition is if the user's guess is in the dictionary, represented by aSet
ofText
.We're using theAsk
ability to provide this information. We'll provide the dictionary to the Ask ability in a later step.
Finally, we provide the user an override option withbasic.overrideLookup
.The dictionary provided doesn't do a great job at identifying pluralized versions of words or past-tense verb forms. (See thechallenge optionsfor some ideas about how to solve this.)
Only if the word is 5 letters long, present in the dictionarySet
,or if the user accepts the override will we then call thebasic.Guess.fromText
function we wrote earlier.