如何处理 Haskell 中的运行时错误?
How to handle runtime errors in Haskell?
我正在尝试通过编写一个简单的控制台国际象棋游戏来学习 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
函数有时会导致程序崩溃,丢失游戏中的所有进度。例如,在 "Your move:" 提示符下按 Enter 会产生:
Your move:
cchess: Prelude.head: empty list
否则,输入两位数会产生:
Your move: 11
cchess: Error in array index
输入两个句点得到:
Your move: ..
cchess: Char.digitToInt: not a digit '.'
我想捕获这些错误并通知用户他们输入的移动不是有效的 SAN 表示法。我该怎么做?
在理想情况下,您会避免使用 head
这样的函数,并且根本不会出现运行时错误。运行时错误从根本上来说很尴尬,尤其是在 Haskell.
中
在这种情况下,您想捕获运行时错误。如果您满足于将它变成 Maybe
,您可以使用 spoon
包。
Haskell 中的异常由于懒惰而变得微妙。特别是,如果您不评估结构中有异常的部分,它就不会触发。这是在 spoon
中用两个不同的函数处理的:
spoon
,它深入评估结构,但需要一个特殊类型类 的实例
teaspoon
只评估你的结构部分 weak head normal form
对于你的情况,我认为 teaspoon
应该没问题。尝试检查解析结果:
teaspoon (moveSAN move board)
这应该会给你一个 Maybe
值。
如果这不起作用,则意味着您需要评估更多结构以触发异常。看起来 Board
没有实现用 spoon
深入评估它所需的类型类,所以你最好的选择有点老套:在 show
的结果上使用 spoon
:
spoon (show $ moveSAN move board)
这会给你一个Maybe String
。如果是 Just
,则此着法解析正确;如果是 Nothing
,则出错。
值得注意的是 spoon
包并没有真正做很多事情:它的每个功能都只有 a couple of lines。在某些时候,自己弄清楚如何处理 Haskell 中的异常是值得的,但现在 spoon
只是更方便一点,应该可以正常工作。
我正在尝试通过编写一个简单的控制台国际象棋游戏来学习 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
函数有时会导致程序崩溃,丢失游戏中的所有进度。例如,在 "Your move:" 提示符下按 Enter 会产生:
Your move:
cchess: Prelude.head: empty list
否则,输入两位数会产生:
Your move: 11
cchess: Error in array index
输入两个句点得到:
Your move: ..
cchess: Char.digitToInt: not a digit '.'
我想捕获这些错误并通知用户他们输入的移动不是有效的 SAN 表示法。我该怎么做?
在理想情况下,您会避免使用 head
这样的函数,并且根本不会出现运行时错误。运行时错误从根本上来说很尴尬,尤其是在 Haskell.
在这种情况下,您想捕获运行时错误。如果您满足于将它变成 Maybe
,您可以使用 spoon
包。
Haskell 中的异常由于懒惰而变得微妙。特别是,如果您不评估结构中有异常的部分,它就不会触发。这是在 spoon
中用两个不同的函数处理的:
spoon
,它深入评估结构,但需要一个特殊类型类 的实例
teaspoon
只评估你的结构部分 weak head normal form
对于你的情况,我认为 teaspoon
应该没问题。尝试检查解析结果:
teaspoon (moveSAN move board)
这应该会给你一个 Maybe
值。
如果这不起作用,则意味着您需要评估更多结构以触发异常。看起来 Board
没有实现用 spoon
深入评估它所需的类型类,所以你最好的选择有点老套:在 show
的结果上使用 spoon
:
spoon (show $ moveSAN move board)
这会给你一个Maybe String
。如果是 Just
,则此着法解析正确;如果是 Nothing
,则出错。
值得注意的是 spoon
包并没有真正做很多事情:它的每个功能都只有 a couple of lines。在某些时候,自己弄清楚如何处理 Haskell 中的异常是值得的,但现在 spoon
只是更方便一点,应该可以正常工作。