wiki:ArrowNotation

Arrow notation

Arrow notation (current documentation) has been in GHC for many years, but it lacks a maintainer. Even Simon PJ is very hazy about how it all works, and even toys with the idea of taking it out altogether.

Apart from the tickets below, there are a number of things that need doing

  • There no single place that describes all the moving parts of the arrow implementation, including both the typechecking and desugaring rules -- and it's very hard to work it out from the code. Simply writing out the typechecking and desugaring rules, with some commentary, would be really helpful. There is a tiny start in Note [Arrow overview] in TcArrows.
  • #13547: work out if existential and GADT pattern matches are allowed. If so, fix the desugarer; if not, reject them with a decent error message, not a Core Lint crash.
  • Lower down this page are a couple of proposed changes to the notation enabled with -XArrows. I'm not sure of their status.

Tickets

Use Keyword = Arrows to ensure that a ticket ends up on these lists.

Open Tickets:

#344
arrow notation: incorrect scope of existential dictionaries
#5267
Missing type checks for arrow command combinators
#5777
core lint error with arrow notation and GADTs
#7828
RebindableSyntax and Arrow
#9985
GHC panic with ViewPatterns and GADTs in a proc pattern
#10582
Tiny bug in lexer around lexing banana brackets
#13547
Lint error in arrows program

Closed Tickets:

#2722
<<loop> when compiling with -O option with ghc-6.10.0.20081019
#3822
guards in arrow notation (Arrows extension) case statement cause compiler panic
#5022
Core Lint error from polymorphic definitions inside arrow rec
#5333
Arrow command combinators and infixr cause the desugarer to fail
#5609
Type checking arrow notation in the presence of deferred constraints
#7071
Refactoring arrows
#8505
Arrows example error

Changing the types of arrow operators (implemented in March 2013, for GHC 7.8)

Currently, the type of each argument of an operator (and its result) is required to have the form

a (...(e,t1), ... tn) t

where e is a polymorphic type variable shared by all these types, but the arrow types a can vary. The User's Guide has these examples:

ArrowPlus a => (<+>) :: a e c -> a e c -> a e c
untilA :: ArrowChoice a => a e () -> a e Bool -> a e ()
handleA :: ... => a e c -> a (e,Ex) c -> a e c
bracketA :: ... => a e b -> a (e,b) c -> a (e,c) d -> a e d
runReader :: ... => a e c -> a' (e,State) c
runState :: ... => a e c -> a' (e,State) (c,State)
bind :: Arrow a => a e b -> a (e,b) c -> a e c
bind_ :: Arrow a => a e b -> a e c -> a e c
cond :: ArrowChoice a => a e b -> a e b -> a (e,Bool) b

The problem is that to work out how many tis there are, the type checker needs to be able to determine whether a type is a pair type or this Skolem variable e, and this can't be done with GHC's new constraint-based type system.

The plan is to re-arrange the shapes of the argument and result types to

a (e, (t1, ... (tn, ())...)) t

For the above examples, the new types will be

ArrowPlus a => (<+>) :: a (e,()) c -> a (e,()) c -> a (e,()) c
untilA :: ArrowChoice a => a (e,()) () -> a (e,()) Bool -> a (e,()) ()
handleA :: ... => a (e,()) c -> a (e,(Ex,())) c -> a (e,()) c
bracketA :: ... => a (e,()) b -> a (e,(b,())) c -> a (e,(c,())) d -> a (e,()) d
runReader :: ... => a (e,()) c -> a' (e,(State,())) c
runState :: ... => a (e,()) c -> a' (e,(State,())) (c,State)
bind :: Arrow a => a (e,()) b -> a (e,(b,())) c -> a (e,()) c
bind_ :: Arrow a => a (e,()) b -> a (e,()) c -> a (e,()) c
cond :: ArrowChoice a => a (e,()) b -> a (e,()) b -> a (e,(Bool,())) b

Now in the cases of (<+>), untilA and bind, the new types are specializations of the old, so those operators will still work, but the others will need to be re-defined with the new types.

Generalizing the types of commands

The translation of many of the different varieties of command does not require the full Arrow class, but rather just

premap :: Arrow a => (b -> b') -> a b' c -> a b c
premap f g = arr f >>> g

So the proposal is to introduce a superclass of Arrow with just this:

class PreArrow a where
    premap :: Arrow a => (b -> b') -> a b' c -> a b c

and require that class instead of Arrow for the types of those constructs. (libraries proposal)

This shouldn't break any code that uses arrows, but will require rewriting of instances of Arrow.

Last modified 8 months ago Last modified on Apr 11, 2017 7:34:34 AM