在学习箭头的过程中,我偶然发现了一个随着时间的推移并没有变得更清晰的点:
从 John Hughes 的论文“Generalizing Monads To Arrows”中,我注意到下面的情况(情况 I)是不可能的,因为参数中的 arrow
f
不能在箭头过程的本地范围内使用。
-- case I
proc (f,x) -> returnA <- f -< x --- here the f is illegal
如果我们有另一个箭头,
otherArrow
,在别处定义,我们可以这样做:
-- case II
proc (f,x) -> returnA <- otherArrow -< x
我理解需要
-<
,就像没有应用箭头一样,可以将 x
应用于其输入。所以我们使用 -<
来实现这一点(案例二)。
但我不明白无法使用
proc
块参数中给出的箭头的原因。 (案例 I 中 f
中的 proc (f,x)
)。
而我的不理解与一个经常使用的术语相冲突:箭头命令。 Papers 坚持认为它并不等同于 Haskell 表达式,并且 Haskell 类型系统不适合使箭头命令成为语言中的一流命令。
我再次不明白是什么事实/属性使它不可能在 Haskell 类型系统中成为一流的。理解这种不可能背后的原因似乎是我需要的洞察力。
鉴于 Ross Paterson 论文中的语法:
exp ::= ...
| proc pat -> cmd
cmd ::= exp -< exp
| form exp cmd1 ... cmdn
| cmd1 op cmd2
| K pat -> cmd
| (cmd)
从这个语法中我不明白这是不可能的原因。
但是根据翻译规则我们有:
proc p -> e1 -< e2 = arr $ \p -> e2 >>> e1 -- if intersect Vars(p) and Vars (e1) is empty
= arr $ \p -> (e1,e2) >>> app -- otherwise
在第一个分支中,我们看到
p
和 e1
中变量的交集应该为空...这个变量范围限制是箭头命令的主要特征吗?我的意思是它背后的原因无法在 Haskell 中使箭头命令成为一流命令?
正如我所问,我的头脑对 arrow-command 和 composition-of-arrows (使用像 >>> 这样的运算符,最终产生箭头本身)和简单的 arrow 之间没有太大区别.
确实,语法似乎太弱,无法指出这个问题。
您基本上已经准确地发现了“Arrow 不如 Monad”强大的原因。 (FTR,我不喜欢这种比较——箭头是一种抽象,它来自与 monad 根本不同的方向,只是如果与
Kleisli
类别一起使用,它们恰好能够支持大多数 monad 操作。)
proc
符号是一种作弊。它允许您为“变量”命名,这些名称不一定对应于实际值(即也可以与 lambda 绑定的东西)。只要您只使用 -<
右侧的那些就可以了,脱糖器将知道如何将其转换为扇出/投影操作。特别是,你的caseII
脱糖为
proc (f,x) -> returnA <- otherArrow -< x
≡ proc fx -> returnA <- otherArrow -< snd fx
≡ id <<< otherArrow <<< arr snd
但是在
caseII
中,您尝试绑定一个虚拟变量f
,它本身代表要在链中使用的箭头。这是一个问题,因为在我们已经拥有这个“变量”的情况下,您无法建立通过管道进行传输的链!