Haskell Arrows 库论文研读 - 第一弹
0.1 Point-free 编程
编写一个统计字符串中指定单词的个数的函数
count w = length . filter (==w) . words
count "hello" "hello world. hello cycoe."
2
如果要实现从一个文件读取字符串,统计单词数并输出到终端,我们尝试在两侧 加上 print
和 readFile
count w = print . length . filter (==w) . words . readFile
<interactive>:33:51-58: error: • Couldn't match type: IO String with: [Char] Expected: FilePath -> String Actual: FilePath -> IO String • In the second argument of ‘(.)’, namely ‘readFile’ In the second argument of ‘(.)’, namely ‘words . readFile’ In the second argument of ‘(.)’, namely ‘filter (== w) . words . readFile’
但是行不通,因为 print
和 readFile
带入了副作用,我们无法通过函数 组合直接去组合他们,但是我们可以借助 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
0.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 (.)
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
上一篇: fcitx 输入法配置
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论