Haskell 中可以定义自定义防护机制吗?
如果您查看 catches
的示例:
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
Handler (\ (ex :: IOException) -> handleIO ex)]
看起来 catches
已经定义了一个自定义机制来匹配模式(两种异常类型)。我是否弄错了,或者可以将其概括为允许定义一个可以采用与特定模式匹配的 lambda 函数的函数吗?
编辑:仅供参考,下面是捕获量的 GHC 来源。如果有人可以阐明它是如何工作的,那就太好了。
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers
catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
where tryHandler (Handler handler) res
= case fromException e of
Just e' -> handler e'
Nothing -> res
If you look at the example for catches
:
f = expr `catches` [Handler (\ (ex :: ArithException) -> handleArith ex),
Handler (\ (ex :: IOException) -> handleIO ex)]
It looks like catches
has defined a custom mechanism to match on patterns (the two exception types). Am I mistaken, or can this be generalized to allow one to define a function that can take lambda functions that match on a certain pattern?
Edit: FYI below is the GHC source for catches. If someone can shed some light on how this works it would be great.
catches :: IO a -> [Handler a] -> IO a
catches io handlers = io `catch` catchesHandler handlers
catchesHandler :: [Handler a] -> SomeException -> IO a
catchesHandler handlers e = foldr tryHandler (throw e) handlers
where tryHandler (Handler handler) res
= case fromException e of
Just e' -> handler e'
Nothing -> res
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
这是起作用的作用域类型变量 GHC 扩展。点击链接了解更多信息。
基本上,您定义一个关于类型的断言,模式必须满足该类型才能匹配。所以,是的,它类似于守卫,但又不完全如此。
这个特定的例子是如何工作的?深入了解 “基础”库的来源发现:
我们看到
IOException
和ArithException
是实现类型类Exception
的不同类型。我们还看到toException/fromException
是一种包装/展开机制,允许将Exception
类型的值转换为IOException
类型的值。 。因此,我们可以这样写:
假设发生了 IOException 当
catchesHandler
处理处理程序列表的第一个元素时,它会调用tryHandler
,后者又调用fromException
。从tryHandler
的定义可以看出,fromException
的返回类型应该与handleArith
的参数相同。另一方面,e
是 Exception 类型,即 - (IOException ...)。因此,类型以这种方式发挥作用(这不是一个有效的 haskell,但我希望您明白我的意思):从
instance Exception IOException ...
立即得出结果是什么都没有
,所以这个处理程序被跳过。出于同样的原因,将调用以下处理程序,因为fromException
将返回(Just (IOException ...))
。因此,您使用了
handleArith
和handleIO
的类型签名来指定何时调用它们,并且fromException/toException
确保事情是这样发生的。如果愿意,您还可以使用范围类型变量在
f
的定义中约束handleIO
和handleArith
的类型。可以说,这可以为您提供更好的可读性。最终确定作用域类型变量并不是这里的主要参与者。它们只是为了方便而使用。玩这种技巧的主要机制是
fromException/toException
和朋友。作用域类型变量只是允许您拥有更类似于保护模式的语法。This is the Scoped Type Variables GHC extension at work. Follow the link to learn more.
Basically, you define an assertion about type that have to be met by the patter before it can match. So, yeah, it is akin to guards, but not completely so.
How this particular example works? Dive into sources of "base" library to find out that:
We see that
IOException
andArithException
are different types implementing the typeclassException
. We also see thattoException/fromException
is a wrapping/unwrapping mechanism that allows one to convert values of typeException
to/from values of typesIOException
,ArithException
, etc.So, we could've written:
Suppose that
IOException
happens. WhencatchesHandler
processes first element of the handlers list, it callstryHandler
, which callsfromException
. From the definition oftryHandler
it follows that return type of thefromException
should be the same as argument ofhandleArith
. On the other hand,e
is of type Exception, namely - (IOException ...). So, the types play out this way (this is not a valid haskell, but I hope that you get my point):From the
instance Exception IOException ...
it follows immediately that the result isNothing
, so this handler is skipped. By the same reasoning the following handler would be called, becausefromException
would return(Just (IOException ...))
.So, you've used type signatures of
handleArith
andhandleIO
to specify when each of them would be called, andfromException/toException
made sure that it happened this way.If you want to, you could also constraint types of
handleIO
andhandleArith
inside the definition off
, using scoped type variables. Arguably, this could give you better readability.Finalizing, Scoped Type Variables are not a primary players here. They are just used for convenience. Main machinery for playing this kind of tricks is
fromException/toException
and friends. Scoped Type Variables just allow you to have syntax which more closely resemble guard patterns.