如何在Haskell中处理运行时错误?

时间:2015-08-17 17:46:41

标签: haskell exception-handling runtime-error

我试图通过编写简单的棋盘游戏来学习Haskell。它显示一个棋盘,并从SAN notation中的标准输入移动。这是我到目前为止所得到的:

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

问题是对moveSAN功能的调用有时会使程序崩溃,从而失去游戏中取得的所有进展。例如,在&#34;您的行动中按Enter键:&#34;提示产生:

Your move: 
cchess: Prelude.head: empty list

否则,输入两位数字会产生:

Your move: 11
cchess: Error in array index

输入两个句点给出:

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

我想捕获这些错误并告知用户他们输入的移动不是有效的SAN表示法。我怎么能这样做?

1 个答案:

答案 0 :(得分:7)

在理想的世界中,你会避免像head这样的函数而根本没有运行时错误。运行时错误从根本上很尴尬,尤其是在Haskell中。

在这种情况下,您希望捕获运行时错误。如果您要将其转换为Maybe,则可以使用spoon包。

由于懒惰,Haskell的异常是微妙的。特别是,如果你不评估具有例外的结构部分,它就不会被激发。这在spoon处理,具有两个不同的功能:

  • spoon,它深入评估结构 但需要特殊类型类的实例
  • teaspoon仅评估您的weak head normal form
  • 的结构部分

对于您的情况,我认为teaspoon应该没问题。尝试使用以下方法检查解析结果:

teaspoon (moveSAN move board)

应该为您提供Maybe值。

如果这不起作用,则意味着您需要评估更多结构以达到异常。看起来Board没有实现使用spoon对其进行深度评估所需的类型类,所以最好的选择是有点hacky:对spoon的结果使用show

spoon (show $ moveSAN move board)

这会给你一个Maybe String。如果是Just,则移动正确解析;如果是Nothing,则会出错。

值得注意的是spoon软件包确实做不了多少:它所拥有的每个函数只有a couple of lines。在某些时候,值得弄清楚如何自己处理Haskell中的异常,但是现在spoon只是更方便一点,应该适合你。