如何从Haskell中的读取功能中捕获没有解析的例外?
在我的Haskell程序中,我想使用getline
函数来阅读用户给出的值。然后,我想使用读取
函数将此值从字符串转换为适当的Haskell类型。如何通过读取
函数引发的解析错误并要求用户重新输入该值?
我认为这不是“ IO错误”是正确的,因为这不是IO系统无法正常运行的错误?这是语义错误,所以我无法使用IO错误处理机制?
In my Haskell program, I want to read in a value given by the user using the getLine
function. I then want to use the read
function to convert this value from a string to the appropriate Haskell type. How can I catch parse errors thrown by the read
function and ask the user to reenter the value?
Am I right in thinking that this is not an "IO Error" because it is not an error caused by the IO system not functioning correctly? It is a semantic error, so I can't use IO error handling mechanisms?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
你不想。您要使用
相反
: em>原因为什么要使用读取而不是捕获
错误
例外是纯代码中的异常是邪恶的,因为它是非常易于尝试捕获它们在错误的位置:请注意,它们只有在被迫而不是之前飞行。定位在哪里可以是非平凡的练习。这就是Haskell程序员喜欢保持其代码总数的原因(原因之一),即终止和例外。您可能需要查看适当的解析框架(例如 parsec )和 haskeline 也是如此。
You don't want to. You want to use reads instead, possibly like that:
(though you might want to error out if the second element of the tuple is not
""
, that is, if there's a remaining string, too)The reason why you want to use reads instead of catching
error
exceptions is that exceptions in pure code are evil, because it's very easy to attempt to catch them in the wrong place: Note that they only fly when they are forced, not before. Locating where that is can be a non-trivial exercise. That's (one of the reasons) why Haskell programmers like to keep their code total, that is, terminating and exception-free.You might want to have a look at a proper parsing framework (e.g. parsec) and haskeline, too.
有
ReadMaybe
和Readeither
满足您的期望。您可以在text.read.read
软件包中找到此功能。There are
readMaybe
andreadEither
that satisfy your expectation. You find this functions inText.Read
package.这是 @barsoap的答案的附录,而不是其他任何东西。
Haskell例外可能会在任何地方抛出,包括纯代码,但可能只会从IO Monad中捕获。为了捕获纯代码抛出的异常,您需要在io语句上使用
catch
尝试,该语句将迫使要评估纯代码。您应该使用比
someSception
更具体的东西,因为那会抓住任何东西。在上面的代码中,尝试
将返回few excepre
如果read> read
无法解析字符串,但它也将返回左例异常
如果试图打印值时有IO错误,或其他可能出错的其他因素(内存等)。现在,这就是为什么纯代码的例外是邪恶的原因。如果IO代码实际上并未迫使要评估的结果怎么办?
如果运行此操作,您会发现您总是最终进入案例语句的分支,无论用户输入了什么。这是因为IO操作传递给
尝试
从未尝试读取
输入的字符串。它打印列表的第一个值data
,它是恒定的,从不触摸列表的尾巴。因此,在案例语句的第一个分支中,编码器认为数据已评估,但没有评估,并且读取
仍然可能会引发异常。读取
是为了不进行简报的数据,而不是解析用户输入的输入。使用读取
,或切换到真实的解析器组合库。我喜欢 uu-parsinglib ,但是,还有许多其他人也很好。无论如何,您很可能需要额外的力量。This is an addendum to @barsoap's answer more than anything else.
Haskell exceptions may be thrown anywhere, including in pure code, but they may only be caught from within the IO monad. In order to catch exceptions thrown by pure code, you need to use a
catch
ortry
on the IO statement that would force the pure code to be evaluated.You should use something more specific than
SomeException
because that will catch anything. In the above code, thetry
will return aLeft exception
ifread
can't parse the string, but it will also return aLeft exception
if there's an IO error when trying to print the value, or any number of other things that could possibly go wrong (out of memory, etc.).Now, here's why exceptions from pure code are evil. What if the IO code doesn't actually force the result to be evaluated?
If you run this, you'll find that you always end up in the
Right
branch of the case statement, no matter what the user entered. This is because the IO action passed totry
doesn't ever try toread
the entered string. It prints the first value of the listdata
, which is constant, and never touches the tail of the list. So in the first branch of the case statement, the coder thinks the data is evaluated but it isn't, andread
may still throw an exception.read
is meant for unserializing data, not parsing user-entered input. Usereads
, or switch to a real parser combinator library. I like uu-parsinglib, but parsec, polyparse, and many others are good too. You'll very likely need the extra power before long anyway.这是一个改进的
Mayberead
,仅允许尾随的空间,但没有其他:Here's an improved
maybeRead
which allows only for trailing whitespaces, but nothing else: