4

我是 Yesod 和 Haskell 的新手,所以请耐心等待,但我有一个程序可以接受文件,计算单词并在新的 Yesod 网页上显示结果。我需要一种更优雅地捕获异常的方法。例如,如果它在隐藏文件上运行以下函数:

wordCount :: String -> String -> String

wordCount ('.' : _) _   = error "Cannot count hidden files."
wordCount name contents = "<p>There are <b>" ++ show (length $ words contents) ++ "</b> words in your file <i>" ++ name ++ "</i>.</p>"

我想显示该错误消息,然后显示表单以供用户提交新文件。现在它只是转到一个页面,上面写着“页面加载时与服务器的连接已重置”。

我认为 Yesod 有自己的一组 catch 函数,我可能不得不隐藏它来编写自己的函数,但我不确定它们会在哪里,而且我在任何文档中都找不到对它们的任何引用。如果用户输入了错误的文件,我不希望网站崩溃。

任何帮助将非常感激。

编辑:感谢您的建议。我意识到以这种方式抛出错误并不是处理错误的最佳方法,但问题实际上是我正在使用通常从终端而不是 Yesod 站点运行的现有 Haskell 代码。我用wordcount作为一个小例子,但实际上它是几十个文件,几十个函数和分散的错误抛出。希望我可以捕获这些,而不必完全修改现有代码中的每个函数。如果有人对如何在 Yesod 中捕获异常有任何建议,我将不胜感激。

4

1 回答 1

3

正如 dflemstr 所说,不要error用于这样的可恢复错误。错误机制类似于undefined-- 它代表一个完全灾难性的错误,例如尚未编写的函数或无限循环。对于您希望永远不会遇到坏情况的部分函数来说这很好,但对于预期和必须处理的错误并不是最佳选择。此外,类型系统不反映您对 的使用error,因此您的函数的使用者无法知道捕获错误。

相反,您应该使用类似MaybeEither表示这样的错误的类型。例如,你可以这样重写这个函数:

wordCount :: String -> String -> Maybe String
wordCount ('.' : _) _   = Nothing
wordCount name contents = Just $ "<p>There are <b>" ++ show (length $ words contents) ++ "</b> words in your file <i>" ++ name ++ "</i>.</p>"

现在,不是返回 a String,而是返回 a Maybe String。这是一个可以通过Nothing或的类型Just StringNothing代表失败——即函数由于输入无效而失败。Just代表成功。

接下来,要“捕获”错误,您可以只进行模式匹配:

case wordCount fileName contents of
  Just res -> res
  Nothing  -> "Cannot count hidden files!"

Data.Maybe中还有一些便利功能,可以让您的代码在常见情况下更整洁。

另一种选择是Either类型。在一个Maybe类型中,Nothing构造函数不携带任何附加信息。您所知道的是该功能失败。Either行为方式相同,除了“失败”案例确实携带任意附加信息。调用“失败”情况,调用Left“成功”情况Right。该类型还有两个参数:错误信息的类型和结果的类型。它看起来像这样:

wordCount :: String -> String -> Either String String
wordCount ('.' : _) _   = Left "You cannot count a hidden file!"
wordCount name contents = Right $ "<p>There are <b>" ++ show (length $ words contents) ++ "</b> words in your file <i>" ++ name ++ "</i>.</p>"

然后您可以像处理结果一样处理结果Maybe。在这种情况下,我认为 aMaybe更可取,因为该功能只有一种方式失败。如果有一堆可能的错误情况,那Either将是一个更好的选择。

于 2012-07-23T19:58:30.337 回答