Haskell语言学习笔记(40)Arrow(1)
Arrow
class Category a => Arrow a where
arr :: (b -> c) -> a b c
first :: a b c -> a (b,d) (c,d)
first = (*** id)
second :: a b c -> a (d,b) (d,c)
second = (id ***)
(***) :: a b c -> a b' c' -> a (b,b') (c,c')
f *** g = first f >>> arr swap >>> first g >>> arr swap
where swap ~(x,y) = (y,x)
(&&&) :: a b c -> a b c' -> a b (c,c')
f &&& g = arr (\b -> (b,b)) >>> f *** g
Arrow(箭头)是个类型类,它是 Category(范畴)的子类。
Arrow 是函数的进一步抽象。
- arr :: (b -> c) -> a b c
arr 函数将函数转换为 Arrow。 - first :: a b c -> a (b,d) (c,d)
first 函数接收一个二元组,然后使用一个 Arrow 来修改元组的第1个成员。 - second :: a b c -> a (d,b) (d,c)
second 函数接收一个二元组,然后使用一个 Arrow 来修改元组的第2个成员。 - (***) :: a b c -> a b' c' -> a (b,b') (c,c')
(***) 函数接收一个二元组,然后分别使用两个 Arrow 来修改这个元组的两个成员。 - (&&&) :: a b c -> a b c' -> a b (c,c')
(&&&) 函数只接收一个参数,拷贝一份,组成一个二元组,然后分别使用两个 Arrow 来修改这个元组的两个成员。
Arrow 的法则
arr id = id
arr (f >>> g) = arr f >>> arr g
first (arr f) = arr (first f)
first (f >>> g) = first f >>> first g
first f >>> arr fst = arr fst >>> f
first f >>> arr (id *** g) = arr (id *** g) >>> first f
first (first f) >>> arr assoc = arr assoc >>> first f
where
assoc ((a,b),c) = (a,(b,c))
(->) 是个 Arrow
instance Arrow (->) where
arr f = f
(***) f g ~(x,y) = (f x, g y)
Prelude Control.Arrow> (+2) &&& (*2) $ 3
(5,6)
Prelude Control.Arrow> (+2) *** (*2) $ (1,3)
(3,6)
Prelude Control.Arrow> (+2) <<< (*2) $ 3
8
Prelude Control.Arrow> (*2) >>> (+2) $ 3
8
Prelude Control.Arrow> first (*2) (1,3)
(2,3)
Prelude Control.Arrow> second (*2) (1,3)
(1,6)
Prelude Control.Arrow> arr (*2) 3
6
Kleisli Arrow
newtype Kleisli m a b = Kleisli { runKleisli :: a -> m b }
instance Monad m => Category (Kleisli m) where
id = Kleisli return
(Kleisli f) . (Kleisli g) = Kleisli (\b -> g b >>= f)
instance Monad m => Arrow (Kleisli m) where
arr f = Kleisli (return . f)
first (Kleisli f) = Kleisli (\ ~(b,d) -> f b >>= \c -> return (c,d))
second (Kleisli f) = Kleisli (\ ~(d,b) -> f b >>= \c -> return (d,c))
Kleisli m a b封装了一个返回值为 Monad 的函数:a -> m b。
如果 m 是 Monad,那么 Kleisli m 是 Category,也是 Arrow。
Prelude Control.Arrow> runKleisli (Kleisli (\x -> [x * 2]) >>> Kleisli (\x -> [x, -x])) 2
[4,-4]
Prelude Control.Monad> (\x -> [x * 2]) >=> (\x -> [x, -x]) $ 2
[4,-4]
Prelude Control.Arrow> runKleisli (arr length >>> Kleisli print) [2,2]
2
Arrow 的函数
returnA :: Arrow a => a b b
returnA = arr id
(^>>) :: Arrow a => (b -> c) -> a c d -> a b d
f ^>> a = arr f >>> a
(>>^) :: Arrow a => a b c -> (c -> d) -> a b d
a >>^ f = a >>> arr f
(<<^) :: Arrow a => a c d -> (b -> c) -> a b d
a <<^ f = a <<< arr f
(^<<) :: Arrow a => (c -> d) -> a b c -> a b d
f ^<< a = arr f <<< a
Prelude Control.Arrow> (returnA :: Int -> Int) 5
5
Prelude Control.Arrow> runKleisli (returnA :: Kleisli [] Int Int) 5
[5]
Prelude Control.Arrow> runKleisli (length ^>> Kleisli print) [2,2]
2
Prelude Control.Arrow> runKleisli (Kleisli print <<^ length) [2,2]
2
Haskell语言学习笔记(40)Arrow(1)的更多相关文章
- 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语言学习笔记(47)Arrow(2)
Function, Monad, Arrow f :: Int -> (Int, Int) f = \x -> let y = 2 * x z1 = y + 3 z2 = y - 5 in ...
- Haskell语言学习笔记(92)HXT
HXT The Haskell XML Toolbox (hxt) 是一个解析 XML 的库. $ cabal install hxt Installed hxt-9.3.1.16 Prelude&g ...
- 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语言学习笔记(49)ByteString Text
Data.ByteString String 是 [Char] 的同义词,在使用上存在List的惰性所带来的性能问题. 在处理大型二进制文件时,可以使用 ByteString 来代替 String. ...
随机推荐
- Spring Cloud 入门 之 Zuul 篇(五)
原文地址:Spring Cloud 入门 之 Zuul 篇(五) 博客地址:http://www.extlight.com 一.前言 随着业务的扩展,微服务会不对增加,相应的其对外开放的 API 接口 ...
- 【数据库】使用JMeter创建数据库(Mysql)测试
我的环境:MySQL:mysql-essential-5.1.51-win32 jdbc驱动:我已经上传到csdn上一个:http://download.csdn.net/detail/paulwin ...
- linux 信号处理 四
一.信号生命周期 从信号发送到信号处理函数的执行完毕 对于一个完整的信号生命周期(从信号发送到相应的处理函数执行完毕)来说,可以分为三个重要的阶段,这三个阶段由四个重要事件来刻画:信号诞生:信号在进程 ...
- 小峰mybatis(5)mybatis使用注解配置sql映射器--动态sql
一.使用注解配置映射器 动态sql: 用的并不是很多,了解下: Student.java 实体bean: package com.cy.model; public class Student{ pri ...
- canvas基础一
使用HTML5中<canvas>元素可以在页面中设定一个区域,然后通过JavaScript动态地在这个区域中绘制图形,要在这块画布(canvas)上绘图,需要取得绘图上下文,而取得绘图上下 ...
- 求交错序列前N项和(15 分)
7-2 求交错序列前N项和(15 分) 本题要求编写程序,计算交错序列 1-2/3+3/5-4/7+5/9-6/11+... 的前N项之和. 输入格式: 输入在一行中给出一个正整数N. 输出格式: 在 ...
- nsenter工具进入docker容器
对于运行在后台的Docker容器,我们经常需要做的事情是进入到容器中,docker为我们提供了docker exec .docker attach 命令,并且还提供了nsenter工具,外部工具供我们 ...
- 1042 Shuffling Machine (20 分)
1042 Shuffling Machine (20 分) Shuffling is a procedure used to randomize a deck of playing cards. Be ...
- win2003 server的域用户加入本地管理员组
很久没有搞windows的域管理,今天碰到一个问题,一直找不到解决方法,一直在网络找资料,直到刚刚才找到方法,方法如下: C:\>net localgroup administrators li ...
- Solr Web增加Basic安全性验证
Solr在5.0版本后,不再提供war包部署的方式,取而代之的是内置了jetty服务, 但是我们发现其中并没有内置任何安全性相关检查,任何人如果知道了我们的外网地址就能直接访问并修改其中的索引 ...