
[英]Why does the Applicative instance for Maybe give Nothing when function is Nothing in <*>
[英]Why does catch not properly invoke handler when using Maybe?
考虑以下 Haskell 代码
try_lex_rgx :: String -> IO (Maybe [RgxToken])
try_lex_rgx rgx_str =
catch
(do
rgx_toks <- evaluate $ lex_rgx rgx_str
return $ Just rgx_toks)
(\(LexerErr err_msg remainder) -> disp_lex_error rgx_str (LexerErr err_msg remainder))
我打算让这段代码工作的方式是评估表达式lex_rgx rgx_str
,在它们发生时捕获任何异常,然后调用disp_lex_error
来漂亮地打印错误。
(顺便说一下,disp_lex_error的代码如下
disp_lex_error :: String -> RgxLexerException -> IO (Maybe [RgxToken])
disp_lex_error rgx_str (LexerErr err_msg remainder) = let loc_str_frag = "In regex " ++ rgx_str ++ " at ..." in
do
hPutStrLn stderr ("Lexer error: " ++ err_msg ++ "\n" ++
loc_str_frag ++ remainder ++ "\n" ++
(replicate (length loc_str_frag - 1) ' ') ++ "^^")
evaluate Nothing
)
但是,我认为懒惰的评估正在阻止这种情况发生。 当我在 ghci 中使用调用错误的输入运行代码时,我收到以下消息
*Rgx.RgxLexer> :l Rgx.RgxLexer
[1 of 2] Compiling Rgx.RgxTok ( Rgx/RgxTok.hs, interpreted )
[2 of 2] Compiling Rgx.RgxLexer ( Rgx/RgxLexer.hs, interpreted )
Ok, two modules loaded.
*Rgx.RgxLexer> try_lex_rgx "\\"
Just [*** Exception: LexerErr "Dangling \"\\\" is not allowed" ""
而不是一个漂亮的印刷错误。
对我来说,似乎代码没有按照我的意图工作,因为由于延迟评估,系统仅在它已经开始形成父表达式Just x
后才实际计算表达式evaluate $ lex_rgx rgx_str
。
我是否正确,如果正确,是否有任何优雅的方法来规避这个问题?
evaluate
仅将值评估为 WHNF(即匹配(:)
或[]
,但不能进一步匹配),但您的错误隐藏在列表的元素内。 以下函数强制列表的所有元素(或使用 deepseq 库以获得更通用的接口)。
-- Evaluates each element to WHNF (which might not be enough for all use cases)
evaluateList :: [a] -> IO [a]
evaluateList xs = evaluate (foldr seq () xs) >> pure xs
然而,在元素中隐藏异常首先是一种有问题的方法,请考虑重构词法分析器以不使用异常,产生一个信息丰富的Either
中继所有可能的错误,而不是使用Maybe
它的Just
甚至不能保证成功解析。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.