Syntactically light-weight call-by-name arguments in PureScript. No guarantees. Completely gratuitous.
This library takes advantage of term-abstraction incurred by type class
dictionaries to approximate call-by-name evaluation for arguments. We
simulate call-by-name by taking a Unit -> a argument which defers evaluation
of a until invoked. We then provide operators to coerce these
type-class-abstracted terms into the more reliable call-by-name form.
Take the when function from Prelude:
when :: forall m. Applicative m => Boolean -> m Unit -> m UnitIt is strict in both arguments, so it will allocate the provided effect
even though it may be discarded. This can be problematic, especially if there
are let bound values:
example =
when that do
let
a = somethingExpensive 42
b = somethingElseExpensive a
this a bBoth a and b will be evaluated, which we don't want. The alternative is to
use a call-by-name approximation:
when :: forall m. Applicative m => Boolean -> (Unit -> m Unit) -> m Unit
example =
when that \_ -> do
let
a = somethingExpensive 42
b = somethingElseExpensive a
this a bBut wow that's irritating. This library exports an application operator \\
that makes this look better.
import CallByName.Applicative (when)
import CallByName.Syntax ((\\))
example =
when that \\do
let
a = somethingExpensive 42
b = somethingElseExpensive a
this a bWe've saved four arduous characters.
There's also the ~ operator which lifts terms into Lazy.
somethingLazy :: Lazy Int -> Int
example =
somethingLazy ~(evaluate expensive int)Versus the old:
example =
somethingLazy (Lazy.defer \_ -> evaluate expensive int)This library also exports some call-by-name variants of functions that don't exist in current Prelude or ecosystem.
CallByName.Applicative.when ::
forall m. Applicative m => Boolean -> (Unit -> m Unit) -> m Unit
CallByName.Applicative.unless ::
forall m. Applicative m => Boolean -> (Unit -> m Unit) -> m Unit
CallByName.Monoid.guard ::
forall m. Monoid m => Boolean -> (Unit -> m) -> mAnd also exports a version of the Alt type class which defers it's second
argument.
class Strict.Alt f <= Alt f where
alt :: forall a. f a -> (Unit -> f a) -> f aThis can be combined with a magic, right-associated version of <|> which
does not strictly evaluate it's second argument.
example =
Just 42 <|> unsafeThrow "Too strict!"