lax-0.0.0: Lax arrowsSource codeContentsIndex
Control.Arrow.Lax
Description

Lax arrows.

In order to get an understanding of what a lax arrow is, consider the following code example:

    looping :: IO ()
    looping = fixIO (\char -> putChar char >> return 'A')

One might expect that executing looping will result in a capital A being printed but that is not the case. The resulting 'A' will become “available” not until the return action has being executed which is after the execution of putChar char. If one thinks of a value of type IO a as being a function of type World -> (a,World) then return is defined as follows:

    return x = \world -> world `seq` (world,x)

However, to make looping work, return would have to be defined as follows:

    return x = \world -> (world,x)

The LaxArrow type constructor transforms a given arrow into a new arrow which works mostly like the base arrow but is “a bit less strict”. To be more precise, all parts of a lax arrow value which are constructed with pure are internally moved to the beginning. This way, data produced by such parts is available at each point in the arrow when loop is used. For the above example, this would mean that the result 'A' is already known before the putChar action is executed and can therefore be used by this action.

Note that relaxation only works for arrows, not directly for monads. It is unknown whether a relaxation mechanism for monads exists but it is considered unlikely. Of course, you can transform any monad into an arrow by using Kleisli. However, the lax arrow type is not an instance of ArrowChoice nor it is one of ArrowApply, and at least the current implementation does not allow it to be an instance of either class.

Further note that the implementation of lax arrows does not use System.IO.Unsafe.unsafePerformIO nor System.IO.Unsafe.unsafeInterleaveIO and is not tied to IO at all.

The lax arrow version of the looping example would be as follows:

    looping :: IO ()
    looping = runKleisli (runLax (loop $ second $ impure (Kleisli putChar) >>> pure (const 'A')))
                         ()
Synopsis
data LaxArrow arrow input output
impure :: ArrowLoop arrow => arrow input output -> LaxArrow arrow input output
runLax :: Arrow arrow => LaxArrow arrow input output -> arrow input output
Documentation
data LaxArrow arrow input output Source
A lax arrow.
show/hide Instances
Arrow arrow => Arrow (LaxArrow arrow)
Arrow arrow => ArrowLoop (LaxArrow arrow)
impure :: ArrowLoop arrow => arrow input output -> LaxArrow arrow input outputSource

Transforms a value of the base arrow type into a lax arrow. Pure parts of the argument arrow are not affected by relaxation, only parts of the lax arrow which are constructed with pure from the LaxArrow instance of Arrow.

lift from the ArrowTransformer class is not used since it is probably supposed to be a homomorphism but impure is not a homomorphism. While impure preserves (>>>), it does not preserve pure, first and loop. If it would then we would have no relaxation effect at all.

runLax :: Arrow arrow => LaxArrow arrow input output -> arrow input outputSource
Converts a lax arrow into a value of the base arrow type.
Produced by Haddock version 2.3.0