During my learning about arrows, I stumble on a point which doesn't get clearer with time:
from John Hughes's paper "Generalizing Monads To Arrows", I have noted that this below (case I) is not possible, because the arrow f
in parameter cannot be used inside the local scope of the arrow procedure.
-- case I
proc (f,x) -> returnA <- f -< x --- here the f is illegal
If we had another arrow, otherArrow
, defined elsewhere, we could do:
-- case II
proc (f,x) -> returnA <- otherArrow -< x
I understand the need for the -<
like there is no apply for arrows so as to apply x
to its input. So we use -<
to achieve this (case II).
But I do not see the reason for the impossibility to use an arrow given in parameter to the proc
block. (f
in proc (f,x)
in the case I).
And my not-understanding collides with a term that is often used: arrow command. Papers insists that it is not equivalent to haskell expressions, and that the Haskell type system is not suited for making arrow commands first-class in the language.
Again I do not see what is the fact/the property that makes it impossible to make it first-class in the Haskell type system. Understanding the reason behind this impossibility seems to be the insight I need.
Given the grammar in Ross Paterson's paper:
exp ::= ...
| proc pat -> cmd
cmd ::= exp -< exp
| form exp cmd1 ... cmdn
| cmd1 op cmd2
| K pat -> cmd
| (cmd)
From this grammar I do not grasp the reason for the impossibility.
But from translation rules we have:
proc p -> e1 -< e2 = arr $ \p -> e2 >>> e1 -- if intersect Vars(p) and Vars (e1) is empty
= arr $ \p -> (e1,e2) >>> app -- otherwise
In the first branch, we see that the intersection of variables in p
and in e1
should be empty... Is this variable scope-limitation the main trait of an arrow command, I mean the reason behind what makes it not possible to make arrow command first-class in Haskell ?
As I am asking, my mind makes not much difference between an arrow-command and a composition-of-arrows (with operators like >>>, which eventually results in an arrow itself) and a simple arrow.
Indeed the grammar appears to be too weak to point out this issue.
You've basically discovered exactly what makes “Arrow less powerful than Monad”. (FTR, I dislike this comparison – arrows are an abstraction that comes from a fundamentally different direction than monads, only they happen to be able to support most monad operations if used with a Kleisli
category.)
proc
notation is a cheat. It allows you to give names to “variables” which don't necessarily correspond to actual values at all (i.e., to something that could also be bound with a lambda). That's ok as long as you only use those to the right of -<
, where the desugarer will know how to translate it to fanout/projection operations. In particular, your caseII
desugars as
proc (f,x) -> returnA <- otherArrow -< x
≡ proc fx -> returnA <- otherArrow -< snd fx
≡ id <<< otherArrow <<< arr snd
But in caseII
, you try to bind a virtual variable f
that itself represents an arrow to be used in the chain. That's a problem, because you can't build up the chain that would pipe through this “variable” withour already having it available!