Haskell语言学习笔记(33)Exception, Except, ExceptT
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的更多相关文章
- Haskell语言学习笔记(88)语言扩展(1)
ExistentialQuantification {-# LANGUAGE ExistentialQuantification #-} 存在类型专用的语言扩展 Haskell语言学习笔记(73)Ex ...
- Haskell语言学习笔记(79)lambda演算
lambda演算 根据维基百科,lambda演算(英语:lambda calculus,λ-calculus)是一套从数学逻辑中发展,以变量绑定和替换的规则,来研究函数如何抽象化定义.函数如何被应用以 ...
- Haskell语言学习笔记(69)Yesod
Yesod Yesod 是一个使用 Haskell 语言的 Web 框架. 安装 Yesod 首先更新 Haskell Platform 到最新版 (Yesod 依赖的库非常多,版本不一致的话很容易安 ...
- Haskell语言学习笔记(20)IORef, STRef
IORef 一个在IO monad中使用变量的类型. 函数 参数 功能 newIORef 值 新建带初值的引用 readIORef 引用 读取引用的值 writeIORef 引用和值 设置引用的值 m ...
- Haskell语言学习笔记(39)Category
Category class Category cat where id :: cat a a (.) :: cat b c -> cat a b -> cat a c instance ...
- Haskell语言学习笔记(72)Free Monad
安装 free 包 $ cabal install free Installed free-5.0.2 Free Monad data Free f a = Pure a | Free (f (Fre ...
- Haskell语言学习笔记(44)Lens(2)
自定义 Lens 和 Isos -- Some of the examples in this chapter require a few GHC extensions: -- TemplateHas ...
- Haskell语言学习笔记(38)Lens(1)
Lens Lens是一个接近语言级别的库,使用它可以方便的读取,设置,修改一个大的数据结构中某一部分的值. view, over, set Prelude> :m +Control.Lens P ...
- Haskell语言学习笔记(92)HXT
HXT The Haskell XML Toolbox (hxt) 是一个解析 XML 的库. $ cabal install hxt Installed hxt-9.3.1.16 Prelude&g ...
随机推荐
- POJ1639顶点度限制最小生成树
题目:http://poj.org/problem?id=1639 见汪汀的<最小生成树问题的拓展>. 大体是先忽略与根节点相连的边,做一遍kruscal,得到几个连通块和一个根节点: 然 ...
- 编程中检查IIS7组件的安装情况
http://learn.iis.net/page.aspx/135/discover-installed-components/说明:ASP.NET网络应用程序在IIS7上部署的时候,经常会要求预装 ...
- HDFS高级开发培训课程之HDFS开发实例课件
前言: 刚刚完成的HDFS高级开发培训课程课件中的一个章节,不知道PPT,如何导出HTML格式,只好批量导出图片,贴图了. 连接管理:建立连接.断开连接.设置连接参数 文件操作:浏览文件.上传文件.下 ...
- 基于jQuery的表单操作
1,文本框的聚焦和失焦 在对文本框进行操作时,通常为了提升用户体验,是用户的操作得到及时的反馈,会在文本框获得焦点时,让其颜色改变,然后在失去焦点时恢复为原来的样式,一般情况下,我们可以通过css的伪 ...
- WebForm Response和Request以及Cookie
Session:每一台电脑访问服务器,都会是独立的一套session,key值都一样,但是内容都是不一样的 以上所有内容,都跟cookies一样, 内置对象:用于页面之间的数据交互 为什么要使用这么内 ...
- [转] Maven.pom.xml 配置示例
<?xml version="1.0" encoding="UTF-8"?> <project xmlns="http://mave ...
- Linux版本使用的文件系统类型
1. cat /etc/fstab 2. df -T -h
- Linux下的压缩(zip)解压(unzip)缩命令
.zip命令 zip -r myfile.zip ./* 将当前目录下的所有文件和文件夹全部压缩成myfile.zip文件,-r表示递归压缩子目录下所有文件. 2.unzip命令 unzip -o ...
- 服务器开启JMX监控
JMX是一个框架,提供了一种功能,可以实时查询应用程序中通过JMX向外部公布的相应参数或者是其他应用程序,同时也可以通过JMX来实时地调用应用程序使用JMX向外部公布的接口,来完成一些功能操作. 如果 ...
- Northwestern European Regional Contest 2017-I题- Installing Apps题解
一.题意 有一个手机,容量为$C$,网上有$N$个app,每个app有个安装包大小$d_i$,有个安装后的占用空间大小$s_i$,安装app是瞬间完成的,即app的占用空间可以瞬间由$d_i$变成$s ...