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. Linux C程序操作Mysql 调用PHP采集淘宝商品 (转)

    还是继续这个项目. 在上一篇Linux下利用Shell使PHP并发采集淘宝产品中,采用shell将对PHP的调用推到后台执行,模拟多线程. 此方法有一致命缺点,只能人工预判每个程序执行时间.如果判断时 ...

  2. LOJ 572 「LibreOJ Round #11」Misaka Network 与求和——min_25筛

    题目:https://loj.ac/problem/572 莫比乌斯反演得 \( ans=\sum\limits_{D=1}^{n}\left\lfloor\frac{n}{D}\right\rflo ...

  3. 二分法查找 (Binary Search)

    二分法查找适用于排列有序的数据.java实现方法如下: // Find the location of a value in array a // Array a must be sorted // ...

  4. openVPN之Luci及tap模式

    一. 1.复制luci-sc-openvpn源码到/home/tingpan/openwrt/barrier_breaker/feeds/luci/applications文件夹下. 二. /home ...

  5. java日期格式转换工具类

    原文地址:http://blog.csdn.net/zhiweianran/article/details/7991531 package com.ace.backoffice.utils; impo ...

  6. 【ActiveMQ入门-8】ActiveMQ学习-与Spring集成

    概述: 下面将介绍如何在Spring下集成ActiveMQ. 消费者:同步接收: 目的地:topic 环境: 主要包括4个文件: HelloSender.java: JMSTest.java: Pro ...

  7. 建造者模式及C++实现

    下面是我自己对建造者模式的理解.具体我还没在开发中应用过,这只是对于书本的理解. 建造者模式 建造者模式:将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示.这是建造者模式的标准 ...

  8. zufeoj Electrification Plan (最小生成树,巧妙设e[i][j]=0)

    Electrification Plan 时间限制: 1 Sec  内存限制: 128 MB提交: 31  解决: 13[提交][状态][讨论版] 题目描述 Some country has n ci ...

  9. javascript创建对象之稳妥构造函数模式(七)

    所谓稳妥对象,指的是没有公共属性,而且其方法也不引用this的对象.稳妥对象最适合在一些安全的环境中(禁止使用this和new)或者在防止数据被其他应用程序改动时. 稳妥构造函数模式有2个特点:1.新 ...

  10. Samba 简介

    SMB 代表的是服务器消息块 (Server Message Block),它是用于在 Windows 上共享文件的协议的原始名称. CIFS 代表公共 Internet 文件系统 (Common I ...