gpt4 book ai didi

haskell - Haskell 中可以定义自定义防护机制吗?

转载 作者:行者123 更新时间:2023-12-03 07:16:33 24 4
gpt4 key购买 nike

如果您查看捕获的示例:

 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

最佳答案

这是Scoped Type Variables GHC 扩展正在工作。点击链接了解更多信息。

基本上,您定义一个关于类型的断言,模式必须满足该类型才能匹配。所以,是的,它类似于守卫,但并不完全如此。

这个特定的例子是如何工作的?深入了解sources of "base" library找出:

class (Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e

data SomeException = forall e . Exception e => SomeException e

instance Exception IOException where
toException = IOException
fromException (IOException e) = Just e
fromException _ = Nothing

instance Exception ArithException where
toException = ArithException
fromException (ArithException e) = Just e
fromException _ = Nothing

我们看到IOExceptionArithException是实现类型类Exception的不同类型。我们还看到 toException/fromException 是一种包装/展开机制,允许将 Exception 类型的值转换为 IOException 类型的值。 、ArithException

所以,我们可以这样写:

f = expr `catches` [Handler handleArith,
Handler handleIO]

handleArith :: ArithException -> IO ()
handleArith ex = ....

handleIO :: IOException -> IO ()
handleIO ex = ....

假设发生IOException。当catchesHandler处理处理程序列表的第一个元素时,它会调用tryHandler,后者又调用fromException。从 tryHandler 的定义可以看出,fromException 的返回类型应该与 handleArith 的参数相同。另一方面,e 是 Exception 类型,即 - (IOException ...)。因此,类型以这种方式发挥作用(这不是有效的 haskell,但我希望您明白我的意思):

fromException :: (IOException ...) -> Maybe ArithException

实例 Exception IOException ... 中,结果立即为 Nothing,因此跳过此处理程序。出于同样的原因,将调用以下处理程序,因为 fromException 将返回 (Just (IOException ...))

因此,您使用了 handleArithhandleIO 的类型签名来指定何时调用它们中的每一个,以及 fromException/toException确保事情以这种方式发生。

如果愿意,您还可以使用范围类型变量在 f 的定义中约束 handleIOhandleArith 的类型。可以说,这可以为您提供更好的可读性。

最终确定的作用域类型变量并不是这里的主要参与者。它们只是为了方便而使用。玩这种技巧的主要机制是 fromException/toException 和 friend 。作用域类型变量只是允许您拥有更类似于保护模式的语法。

关于haskell - Haskell 中可以定义自定义防护机制吗?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/2270699/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com