Cycoe@Home

Haskell Arrows 库论文研读——第一弹

1. Point-free 编程

编写一个统计字符串中指定单词的个数的函数

count w = length . filter (==w) . words
count "hello" "hello world. hello cycoe."

如果要实现从一个文件读取字符串,统计单词数并输出到终端,我们尝试在两侧 加上 printreadFile

count w = print . length . filter (==w) . words . readFile

但是行不通,因为 printreadFile 带入了副作用,我们无法通过函数 组合直接去组合他们,但是我们可以借助 Monad 去进行绑定

count w = (>>= print) .
          liftM (length . filter (==w) . words) .
          readFile

在 Haskell 中,副作用使用 a -> IO b 表示,可以使用以下类型同构表示

type Kleisli m a b = a -> m b

文件读取与输出函数可以进行如下重构

readFile :: Kleisli IO String String
print :: Show a => Kleisli IO a ()

那么函数组合可以定义为如下函数

(>>>) : Monad m => Kleisli m a b -> Kleisli m b c -> Kleisli m a c
(f >>> g) a = do b <- f a
                 g b

打印文件的函数可由 >>> 进行组合

printFile = readFile >>> print

和 Monad 的 return 函数类似, Kleisli 也有对应接口 arr 将一个普通 函数包装成 Kleisli 类型

arr :: Monad m => (a -> b) -> Kleisli m a b
arr f = return . f

使用这些组合子组合副作用和纯函数

count w = readFile >>>
          arr words >>> arr (filter (==w)) >>> arr length >>>
          print

2. Arrow 类型类

Arrow 类型类表示实现了 arr>>> 接口的类型

class Arrow arr where
  arr :: (a -> b) -> arr a b
  arr = id
  (>>>) :: arr a b -> arr b c -> arr a c
  (>>>) = flip (.)
Author: Cycoe (cycoejoo@163.com)
Date: <2022-10-23 Sun 15:17>
Generator: Emacs 29.1 (Org mode 9.6.6)
Built: <2024-01-27 Sat 21:20>