Exception

class (Typeable e, Show e) => Exception e where
toException :: e -> SomeException
fromException :: SomeException -> Maybe e toException = SomeException
fromException (SomeException e) = cast e displayException :: e -> String
displayException = show instance Exception SomeException where
toException se = se
fromException = Just
displayException (SomeException e) = displayException e

ExceptT Monad转换器

newtype ExceptT e m a = ExceptT (m (Either e a))

instance (Monad m) => Monad (ExceptT e m) where
return a = ExceptT $ return (Right a)
m >>= k = ExceptT $ do
a <- runExceptT m
case a of
Left e -> return (Left e)
Right x -> runExceptT (k x) runExceptT :: ExceptT e m a -> m (Either e a)
runExceptT (ExceptT m) = m
  • newtype ExceptT e m a = ExceptT (m (Either e a))

    ExceptT 类型是个 newtype,也就是对现有类型的封装。该类型有两个类型参数:内部 Monad 类型 m 以及基础 Monad Either 的参数类型 e 和 a。

    ExceptT e m a 封装了一个 m (Either e a) 类型的值,通过 runExceptT 函数可以取出这个值。
  • instance (Monad m) => Monad (ExceptT e m) where

    如果 m 是个 Monad,那么 ExceptT e m 也是一个 Monad。

    对比 Monad 类型类的定义,可知 return 函数的类型签名为:

    return :: a -> ExceptT e m a

    大致相当于 a -> m (Either e a)

    而 bind 操作符的类型签名为:

    (>>=) :: ExceptT e m a -> (a -> ExceptT e m b) -> ExceptT e m b

    大致相当于 m (Either e a) -> (a -> m (Either e b)) -> m (Either e b)
  • return a = ExceptT $ return (Right a)

    return 函数首先将 Right a 封装进内部 Monad m 中,然后再把它封装进 ExceptT 这个 Monad 转换器之中。

    这里左侧的 return 是 ExceptT 这个 Monad 的 return,而右侧的 return 是内部 Monad m 的 return。
  • m >>= k = ExceptT $ do

    对比函数签名,可知 m 的类型是 ExceptT e m a,大致相当于 m (Either e a)

    而 k 的类型是 a -> ExceptT e m b,大致相当于 a -> m (Either e b)
  • a <- runExceptT m

    对比 m 的类型,可知 a 的类型是 Either e a

    这是因为 runMaybeT 函数让 m 脱离了 ExceptT Monad, 而 <- 运算符又让 runExceptT m 脱离了内部 Monad m。
  • case a of
  • Left e -> return (Left e)

    这里 return 是内部 Monad m 的 return,所以 return (Left e) 的类型是 m (Either e a)。
  • Right x -> runExceptT (k x)

    k 的类型是 a -> ExceptT e m b

    所以 k x 的类型是 ExceptT e m b

    而 runExceptT (k x) 的类型是 m (Either e b)
证明 ExceptT e m 符合 Monad 法则。
1. return a >>= f ≡ f a
return a >>= f
≡ (ExceptT $ return (Right a)) >>= f
≡ ExceptT (m (Right a)) >>= f
≡ ExceptT $ runExceptT (f a)
≡ f a
2. m >>= return ≡ m
ExceptT (m (Right x)) >>= return
≡ ExceptT $ runExceptT (return x)
≡ ExceptT (m (Right x))
ExceptT (m (Left e)) >>= return
≡ ExceptT $ runExceptT (return (Left e))
≡ ExceptT (m (Left e))
3. (m >>= f) >>= g ≡ m >>= (\x -> f x >>= g)
(ExceptT (m (Right x)) >>= f) >>= g ≡ f x >>= g
(ExceptT (m (Left e)) >>= f) >>= g ≡ ExceptT (m (Left e)) >>= g ≡ ExceptT (m (Left e))
ExceptT (m (Right x) >>= (\x -> f x >>= g) ≡ (\x -> f x >>= g) x ≡ f x >>= g
ExceptT (m (Left e)) >>= (\x -> f x >>= g) ≡ ExceptT (m (Left e))

lift, liftIO 函数

instance MonadTrans (ExceptT e) where
lift = ExceptT . liftM Right instance (MonadIO m) => MonadIO (ExceptT e m) where
liftIO = lift . liftIO
证明 MaybeT 中 lift 函数的定义符合 lift 的法则。
1. lift . return ≡ return
lift . return $ a
≡ ExceptT . liftM Right . return $ a
≡ ExceptT (m (Right a))
≡ return a
2. lift (m >>= f) ≡ lift m >>= (lift . f)
假设 m = n a 并且 f a = n b
于是 m >>= f = n b
lift (m >>= f)
≡ ExceptT . liftM Right $ m >>= f
≡ ExceptT . liftM Right $ n b
≡ ExceptT (n (Right b))
lift m >>= (lift . f)
≡ (ExceptT . liftM Right $ m) >>= (ExceptT . liftM Right . f)
≡ (ExceptT (n (Right a))) >>= (\x -> ExceptT . liftM Right . f $ x)
≡ ExceptT $ runExceptT $ ExceptT . liftM Right . f $ a
≡ ExceptT $ runExceptT $ ExceptT . liftM Right $ n b
≡ ExceptT $ runExceptT $ ExceptT (n (Right b))
≡ ExceptT (n (Right b))

Except Monad

type Except e = ExceptT e Identity

Except Monad 是 ExceptT Monad(转换器) 的一个特例。

应用实例

-- https://stackoverflow.com/questions/26385809/catch-someexception-with-exceptt
-- cabal install lifted-base import Control.Exception.Lifted
import Control.Monad.Trans.Except badFunction :: ExceptT SomeException IO ()
badFunction = throw DivideByZero intercept
:: ExceptT SomeException IO a
-> ExceptT SomeException IO a
intercept a = do
r <- try $ a
case r of
Right x -> return x
Left e -> throwE e intercept'
:: ExceptT SomeException IO a
-> ExceptT SomeException IO a
intercept' = handle throwE main :: IO ()
main = do
r <- runExceptT $ intercept badFunction
case r of Left _ -> putStrLn "caught error"
Right _ -> putStrLn "nope, didn't catch no error"

Haskell语言学习笔记(33)Exception, Except, ExceptT的更多相关文章

  1. Haskell语言学习笔记(88)语言扩展(1)

    ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...

  2. Haskell语言学习笔记(79)lambda演算

    lambda演算 根据维基百科,lambda演算(英语:lambda calculus,λ-calculus)是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义.函数如何被应用以 ...

  3. Haskell语言学习笔记(69)Yesod

    Yesod Yesod 是一个使用 Haskell 语言的 Web 框架. 安装 Yesod 首先更新 Haskell Platform 到最新版 (Yesod 依赖的库非常多,版本不一致的话很容易安 ...

  4. Haskell语言学习笔记(20)IORef, STRef

    IORef 一个在IO monad中使用变量的类型. 函数 参数 功能 newIORef 值 新建带初值的引用 readIORef 引用 读取引用的值 writeIORef 引用和值 设置引用的值 m ...

  5. Haskell语言学习笔记(39)Category

    Category class Category cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c instance ...

  6. Haskell语言学习笔记(72)Free Monad

    安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Fre ...

  7. Haskell语言学习笔记(44)Lens(2)

    自定义 Lens 和 Isos -- Some of the examples in this chapter require a few GHC extensions: -- TemplateHas ...

  8. Haskell语言学习笔记(38)Lens(1)

    Lens Lens是一个接近语言级别的库,使用它可以方便的读取,设置,修改一个大的数据结构中某一部分的值. view, over, set Prelude> :m +Control.Lens P ...

  9. Haskell语言学习笔记(92)HXT

    HXT The Haskell XML Toolbox (hxt) 是一个解析 XML 的库. $ cabal install hxt Installed hxt-9.3.1.16 Prelude&g ...

随机推荐

  1. 非root用户执行程序---sudo的使用

    场景 在应用部署过程中,会遇到这样的问题:前期需要root用户执行配置.初始化工作,而具体的业务应用需要使用非root用户启动. 如何解决呢? 方法 可以使用sudo,实现授权. sudo命令授权,既 ...

  2. MySql检测阻塞,锁等待sql

    ------------ 1分钟内产生binlog大小计算 select @a1:=VARIABLE_VALUE as a1from information_schema.GLOBAL_STATUSw ...

  3. java 网络编程TCP

    客户端 服务端

  4. linux svn服务器(一)

    先安装 参考文章http://www.cnblogs.com/zhaoyang-1989/articles/3455481.html

  5. [UE4]OnComponentBeginOverlap.AddDynamic 的编译错误

    以 Character 类为例,假设有 PacManCharacter 派生自 Character类首先在 PacManCharacter.h 头文件中添加碰撞函数的声明: OnCollision 为 ...

  6. ZooKeeper系列(2) 安装部署 (转)

    原文地址:http://www.cnblogs.com/wuxl360/p/5817489.html 一.Zookeeper的搭建方式 Zookeeper安装方式有三种,单机模式和集群模式以及伪集群模 ...

  7. 【Python编程:从入门到实践】chapter8 函数

    chapter8 函数 8.6 将函数存储在模块中 8.6.1 导入整个模块 要让函数是可导入的,的先创建模块.模块 的扩展名为.py的文件 import pizza 8.6.2 到导入特定的函数 f ...

  8. [ffmpeg_3.3.2]demuxing_decoding.c

    分析ffmpeg3.3.2的example: 由于ffmpeg文档比较少,而且API变化表较大,所以个人首先从ffmpeg自带的demo开始分析,分析(demuxing_decoding.c) 1:首 ...

  9. linux虚拟机Ubuntu命令配置

    # netstat -ntl  # 查看端口号,改成 0.0.0.0才能进行远程访问 # sudo service redis-server restart  # 修改后需要重启服务 python2和 ...

  10. hive 上篇

    hive 是以hadoop为基础的数据仓库,使用HQL查询存放在HDFS上面的数据,HSQL是一种类SQL的语句,最终会被编译成map/reduce,HSQL可以查询HDFS上面的数据:不支持记录级别 ...