REPL
- Allows writing e.g.
functionOf do ...instead offunctionOf $ do. voidis a convenient function, which turnsIO atoIO (). Used here because we don't care about the output of the repl, and in fact that output is never reached, because the repl runs a loop indefinitely.forevertakes a value of typem X(wheremhas aMonadconstraint on it) and loops it:forever mX = mX >> forever mX. It's a clean way to write a for-loop.- Get a line from the user.
- Parse the user's input, using
parsefrom theParsermodule. - Get the current state of the board.
hidingis convenient for avoiding namespace conflicts.pureis likereturn, but only requires theApplicativetypeclass. It can be used almost everywhere thatreturnis used, but is strictly more general, because aMonadconstraint implies anApplicativeconstraint.catchError, here used in infix form, stops an error percolating to the top level. This is useful here, because an uncaught error would haltmain, and so exit the repl.- Neither
returnnorpureis a keyword, and a block ofdo-notationdoes not need to end with it. All that is needed at the end of the "do-block" is a value of typem a(for the monadmin question), anddisplayLine resulthas that type. catchErrorchooses what to do with the error it catches, and one option is to throw it again. It does this for errors includingExit, in order to exit the repl on ":q".runReplWithBoardis the function responsible for "unpacking" the monadic value into something simpler. This is sometimes referred to as "running the side effects" of a program.flipis a useful function that takes a function of typeX -> Y -> Zand flips the argument order to give a function of typeY -> X -> Z. It is often useful when writing in pointfree style.- It is often useful to lift the type
IO Xto the more abstractMonadIO m => m X, which is whatliftIOdoes.
Analysis¶
This module is responsible for producing the actual runnable program (of type IO ()) that wraps up the whole system.
main¶
```haskell
main :: IO () main = void $ runReplWithBoard $ displayLine "Welcome!\n\n" >> forever do
line <- requestLine "> "
let instruction = parse line
board <- get
result <-
case instruction of
Left (ParseError err) -> pure err
Left (ReplError err) -> pure err
Right instr -> evaluate instr
`catchError` ( \case
ReplError txt -> pure txt
err -> throwError err
)
displayLine result
```
```haskell
main :: IO () main = runReplWithBoard $ displayLine "Welcome!\n\n" >> loop where
loop = do
line <- requestLine "> "
let instruction = parse line
board <- get
result <-
case instruction of
Left (ParseError err) -> pure err
Left (ReplError err) -> pure err
Right instr -> evaluate instr
`catchError` ( \case
ReplError txt -> pure txt
err -> throwError err
)
displayLine result
loop
```
```haskell
main :: IO () main = do runReplWithBoard $ displayLine "Welcome!\n\n" >> forever do
line <- requestLine "> "
let instruction = parse line
board <- get
result <-
case instruction of
Left (ParseError err) -> pure err
Left (ReplError err) -> pure err
Right instr -> evaluate instr
`catchError` ( \case
ReplError txt -> pure txt
err -> throwError err
)
displayLine result
pure ()
```
Last update:
February 9, 2023
Created: January 8, 2023
Created: January 8, 2023