Haskell/Arrows
外观
< Haskell
箭头是单子的推广:每个单子都会产生一个箭头,但并非所有箭头都会产生单子。它们与单子有着相同的目的——为库提供通用结构——但更为通用。特别是,它们允许部分静态(独立于输入)或可能接受多个输入的计算概念。如果你的应用程序可以用单子很好地工作,你最好坚持使用它们。但如果你正在使用一个非常类似于单子但不是单子的结构,那么它可能就是一个箭头。
让我们首先了解箭头的表示法。我们将使用最简单的箭头(函数)并构建一些玩具程序,其目的仅仅是为了熟悉语法。
打开你的文本编辑器并创建一个 Haskell 文件,比如 toyArrows.hs
{-# LANGUAGE Arrows #-}
import Control.Arrow (returnA)
idA :: a -> a
idA = proc a -> returnA -< a
plusOne :: Int -> Int
plusOne = proc a -> returnA -< (a+1)
这些是我们前两个箭头。第一个是箭头形式的恒等函数,第二个稍微更有趣,是一个将输入加一的箭头。在 GHCi 中加载它,使用 -XArrows 扩展并查看会发生什么。
% ghci -XArrows toyArrows.hs ___ ___ _ / _ \ /\ /\/ __(_) / /_\// /_/ / / | | GHC Interactive, version 6.4.1, for Haskell 98. / /_\\/ __ / /___| | http://www.haskell.org/ghc/ \____/\/ /_/\____/|_| Type :? for help. Loading package base-1.0 ... linking ... done. Compiling Main ( toyArrows.hs, interpreted ) Ok, modules loaded: Main. *Main> idA 3 3 *Main> idA "foo" "foo" *Main> plusOne 3 4 *Main> plusOne 100 101
的确令人激动。到目前为止,我们已经在箭头表示法中看到了三个新的构造
- 关键字
proc
-<
- 导入的函数
returnA
既然我们已经知道如何将一个值加一,让我们尝试一个更困难的两倍的尝试:加二
plusOne = proc a -> returnA -< (a+1)
plusTwo = proc a -> plusOne -< (a+1)
一个简单的做法是将 (a+1) 作为输入提供给 plusOne
箭头。注意 plusOne
和 plusTwo
之间的相似性。你应该注意到这里有一个基本模式,它有点类似于:proc FOO -> SOME_ARROW <- (SOMETHING_WITH_FOO)
练习 |
---|
|
我们当前的 plusTwo
实现实际上相当令人失望……它不应该只是 plusOne
两次吗?我们可以做得更好,但要做到这一点,我们需要引入 do 标记
plusTwoBis =
proc a -> do b <- plusOne -< a
plusOne -< b
现在在 GHCi 中试试这个
Prelude> :r Compiling Main ( toyArrows.hs, interpreted ) Ok, modules loaded: Main. *Main> plusTwoBis 5 7
你可以使用这个 do 标记构建任意长的序列
plusFive =
proc a -> do b <- plusOne -< a
c <- plusOne -< b
d <- plusOne -< c
e <- plusOne -< d
plusOne -< e
- FIXME:我不确定,但我相信这里的意图是展示使用这个 proc 标记与仅仅使用一个常规的 do 链的区别
本节是一个 存根。你可以通过 扩展它 来帮助 Haskell。 |