How to handle runtime errors in Haskell?

I am trying to learn Haskell by writing a simple console chess game. It displays a chessboard and takes steps from standard input in SAN notations . Here is what I have so far:

import System.IO import Chess import Chess.FEN main = do putStrLn "Welcome to Console Chess!" putStrLn $ show defaultBoard gameLoop defaultBoard gameLoop board = do putStr "Your move: " hFlush stdout move <- getLine let newBoard = moveSAN move board case newBoard of Left _ -> do putStrLn "Invalid move, try again..." gameLoop board Right b -> do putStrLn $ show b gameLoop b 

The problem is that calling the moveSAN function sometimes causes the program to crash, losing all the progress made in the game. For example, pressing Enter at the prompt "Your move:" calls:

 Your move: cchess: Prelude.head: empty list 

Otherwise, entering a two-digit number causes:

 Your move: 11 cchess: Error in array index 

Entering two periods gives:

 Your move: .. cchess: Char.digitToInt: not a digit '.' 

I would like to catch these errors and inform the user that the transition he entered does not correspond to the actual SAN note. How can i do this?

+6
source share
1 answer

In an ideal world, you should avoid functions like head and have no errors at all at runtime. Runtime errors are mostly inconvenient , especially in Haskell.

In this case, you want to catch the runtime error. If you want to turn it into Maybe , you can use the spoon package.

Haskell's exceptions are subtle due to laziness. In particular, if you do not evaluate the part of the structure that has an exception, it does not work. This is done in a spoon with two different functions:

  • spoon , which deeply evaluates the structure, but requires an instance of a special type
  • teaspoon that evaluates your structural part of the path of a weak normal head shape

In your case, I think teaspoon should be fine. Try checking the result of the analysis:

 teaspoon (moveSAN move board) 

which should give you a Maybe value.

If this does not work, it means that you need to evaluate more structure in order to get into the exception. Board doesn't seem to implement the class needed for a deep evaluation with spoon , so your best bet is a bit hacked: use spoon for the show result:

 spoon (show $ moveSAN move board) 

This will give you Maybe String . If he is Just , the move will be correct; if it is Nothing , an error has occurred.

It is worth noting that the spoon package is actually not very much: each function has only a couple of lines . At some point, it's worth figuring out how to handle exceptions in Haskell yourself, but for now, spoon just a little more convenient and should work correctly for you.

+7
source

All Articles