wiki:ArrowNotation

Version 3 (modified by ross, 10 months ago) (diff)

note first change implemented

Proposed changes to arrow notation

This page describes a couple of proposed changes to the notation enabled with -XArrows. (current documentation)

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.