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)的更多相关文章

  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语言学习笔记(47)Arrow(2)

    Function, Monad, Arrow f :: Int -> (Int, Int) f = \x -> let y = 2 * x z1 = y + 3 z2 = y - 5 in ...

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

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

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

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

  9. Haskell语言学习笔记(49)ByteString Text

    Data.ByteString String 是 [Char] 的同义词,在使用上存在List的惰性所带来的性能问题. 在处理大型二进制文件时,可以使用 ByteString 来代替 String. ...

随机推荐

  1. JUC集合之 CopyOnWriteArrayList

    CopyOnWriteArrayList介绍 它相当于线程安全的ArrayList.和ArrayList一样,它是个可变数组:但是和ArrayList不同的时,它具有以下特性: 它最适合于具有以下特征 ...

  2. django 获取前端获取render模板渲染后的html

    function GetProxyServerByGroup(ths, action){ var _html = $.ajax({ url: "/nginx/get_proxy_server ...

  3. net core 2.0学习笔记(一):开发运行环境搭建 (转)

    期待已久的.net core 2.0终于发布了!大家等的花儿都谢了. 不过比预期提前了一个多月,这在微软历史上还真的不多见.按照历史经验看,2.0版本应该比较靠谱,我猜这也是社区非常火爆的原因吧.下面 ...

  4. POJ1179 Polygon

    题目:http://poj.org/problem?id=1179 石子合并的升级版.有负值.但运算符只有 + 和 * . 考虑负值对原做法正确性的影响:之所以仅记录最大值可能不对,是因为有可能负数 ...

  5. x86 openwrt虚拟路由代理上网

    一.代理服务器设置 1.下载代理软件CCProxy 6.8 Build 2.设置如下 二.x86 路由设置 1.在/etc目录下编辑profile http_proxy= https_proxy= f ...

  6. MySQL 中间件 mycat 的使用

    什么是MYCAT 一个彻底开源的,面向企业应用开发的大数据库集群 支持事务.ACID.可以替代MySQL的加强版数据库 一个可以视为MySQL集群的企业级数据库,用来替代昂贵的Oracle集群 一个融 ...

  7. linux 线程的同步 一 (互斥量和信号量)

    互斥量(Mutex) 互斥量表现互斥现象的数据结构,也被当作二元信号灯.一个互斥基本上是一个多任务敏感的二元信号,它能用作同步多任务的行为,它常用作保护从中断来的临界段代码并且在共享同步使用的资源. ...

  8. 好强大的vim配置文件

    原文链接 http://www.cnblogs.com/ma6174/archive/2011/12/10/2283393.html

  9. php如何分割字符串?php mb_substr分割字条串,解决中文乱码问题,支持分割中文! (转)

    因为网站开发需要,必须有一项功能可以把字符串一个一个分割开来,并且转换为数组. 刚开始用“str_split函数”在实验分割中文字符时就出现了乱码. 蚂蚁学院经过一翻研究,最终发现以下方法可以有效分割 ...

  10. 峰Spring4学习(1)HelloWorld

    HelloWorld.java: package com.cy.test; public class HelloWorld { public void say(){ System.out.printl ...