Effect.Uncurried
This module defines types for effectful uncurried functions, as well as functions for converting back and forth between them.
This makes it possible to give a PureScript type to JavaScript functions such as this one:
function logMessage(level, message) {
console.log(level + ": " + message);
}
In particular, note that logMessage
performs effects immediately after
receiving all of its parameters, so giving it the type Data.Function.Fn2
String String Unit
, while convenient, would effectively be a lie.
One way to handle this would be to convert the function into the normal PureScript form (namely, a curried function returning an Effect action), and performing the marshalling in JavaScript, in the FFI module, like this:
-- In the PureScript file:
foreign import logMessage :: String -> String -> Effect Unit
// In the FFI file:
exports.logMessage = function(level) {
return function(message) {
return function() {
logMessage(level, message);
};
};
};
This method, unfortunately, turns out to be both tiresome and error-prone. This module offers an alternative solution. By providing you with:
- the ability to give the real
logMessage
function a PureScript type, and - functions for converting between this form and the normal PureScript form,
the FFI boilerplate is no longer needed. The previous example becomes:
-- In the PureScript file:
foreign import logMessageImpl :: EffectFn2 String String Unit
// In the FFI file:
exports.logMessageImpl = logMessage
You can then use runEffectFn2
to provide a nicer version:
logMessage :: String -> String -> Effect Unit
logMessage = runEffectFn2 logMessageImpl
(note that this has the same type as the original logMessage
).
Effectively, we have reduced the risk of errors by moving as much code into PureScript as possible, so that we can leverage the type system. Hopefully, this is a little less tiresome too.
Here's a slightly more advanced example. Here, because we are using
callbacks, we need to use mkEffectFn{N}
as well.
Suppose our logMessage
changes so that it sometimes sends details of the
message to some external server, and in those cases, we want the resulting
HttpResponse
(for whatever reason).
function logMessage(level, message, callback) {
console.log(level + ": " + message);
if (level > LogLevel.WARN) {
LogAggregatorService.post("/logs", {
level: level,
message: message
}, callback);
} else {
callback(null);
}
}
The import then looks like this:
foreign import logMessageImpl
EffectFn3
String
String
(EffectFn1 (Nullable HttpResponse) Unit)
Unit
And, as before, the FFI file is extremely simple:
exports.logMessageImpl = logMessage
Finally, we use runEffectFn{N}
and mkEffectFn{N}
for a more comfortable
PureScript version:
logMessage ::
String ->
String ->
(Nullable HttpResponse -> Effect Unit) ->
Effect Unit
logMessage level message callback =
runEffectFn3 logMessageImpl level message (mkEffectFn1 callback)
The general naming scheme for functions and types in this module is as follows:
EffectFn{N}
means, an uncurried function which accepts N arguments and performs some effects. The first N arguments are the actual function's argument. The last type argument is the return type.runEffectFn{N}
takes anEffectFn
of N arguments, and converts it into the normal PureScript form: a curried function which returns an Effect action.mkEffectFn{N}
is the inverse ofrunEffectFn{N}
. It can be useful for callbacks.
#EffectFn8
#EffectFn9
#EffectFn10
#mkEffectFn1
mkEffectFn1 :: forall a r. (a -> Effect r) -> EffectFn1 a r
#mkEffectFn2
mkEffectFn2 :: forall a b r. (a -> b -> Effect r) -> EffectFn2 a b r
#mkEffectFn3
mkEffectFn3 :: forall a b c r. (a -> b -> c -> Effect r) -> EffectFn3 a b c r
#mkEffectFn4
mkEffectFn4 :: forall a b c d r. (a -> b -> c -> d -> Effect r) -> EffectFn4 a b c d r
#mkEffectFn5
mkEffectFn5 :: forall a b c d e r. (a -> b -> c -> d -> e -> Effect r) -> EffectFn5 a b c d e r
#mkEffectFn6
mkEffectFn6 :: forall a b c d e f r. (a -> b -> c -> d -> e -> f -> Effect r) -> EffectFn6 a b c d e f r
#mkEffectFn7
mkEffectFn7 :: forall a b c d e f g r. (a -> b -> c -> d -> e -> f -> g -> Effect r) -> EffectFn7 a b c d e f g r
#mkEffectFn8
mkEffectFn8 :: forall a b c d e f g h r. (a -> b -> c -> d -> e -> f -> g -> h -> Effect r) -> EffectFn8 a b c d e f g h r
#mkEffectFn9
mkEffectFn9 :: forall a b c d e f g h i r. (a -> b -> c -> d -> e -> f -> g -> h -> i -> Effect r) -> EffectFn9 a b c d e f g h i r
#mkEffectFn10
mkEffectFn10 :: forall a b c d e f g h i j r. (a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> Effect r) -> EffectFn10 a b c d e f g h i j r
#runEffectFn1
runEffectFn1 :: forall a r. EffectFn1 a r -> a -> Effect r
#runEffectFn2
runEffectFn2 :: forall a b r. EffectFn2 a b r -> a -> b -> Effect r
#runEffectFn3
runEffectFn3 :: forall a b c r. EffectFn3 a b c r -> a -> b -> c -> Effect r
#runEffectFn4
runEffectFn4 :: forall a b c d r. EffectFn4 a b c d r -> a -> b -> c -> d -> Effect r
#runEffectFn5
runEffectFn5 :: forall a b c d e r. EffectFn5 a b c d e r -> a -> b -> c -> d -> e -> Effect r
#runEffectFn6
runEffectFn6 :: forall a b c d e f r. EffectFn6 a b c d e f r -> a -> b -> c -> d -> e -> f -> Effect r
#runEffectFn7
runEffectFn7 :: forall a b c d e f g r. EffectFn7 a b c d e f g r -> a -> b -> c -> d -> e -> f -> g -> Effect r
#runEffectFn8
runEffectFn8 :: forall a b c d e f g h r. EffectFn8 a b c d e f g h r -> a -> b -> c -> d -> e -> f -> g -> h -> Effect r
#runEffectFn9
runEffectFn9 :: forall a b c d e f g h i r. EffectFn9 a b c d e f g h i r -> a -> b -> c -> d -> e -> f -> g -> h -> i -> Effect r
#runEffectFn10
runEffectFn10 :: forall a b c d e f g h i j r. EffectFn10 a b c d e f g h i j r -> a -> b -> c -> d -> e -> f -> g -> h -> i -> j -> Effect r
Modules
- Control.Alt
- Control.Alternative
- Control.Applicative
- Control.Apply
- Control.Biapplicative
- Control.Biapply
- Control.Bind
- Control.Category
- Control.Comonad
- Control.Extend
- Control.Lazy
- Control.Monad
- Control.Monad.Gen
- Control.Monad.Gen.Class
- Control.Monad.Gen.Common
- Control.Monad.Rec.Class
- Control.Monad.ST
- Control.Monad.ST.Class
- Control.Monad.ST.Global
- Control.Monad.ST.Internal
- Control.Monad.ST.Ref
- Control.MonadPlus
- Control.MonadZero
- Control.Plus
- Control.Semigroupoid
- Data.Array
- Data.Array.NonEmpty
- Data.Array.NonEmpty.Internal
- Data.Array.Partial
- Data.Array.ST
- Data.Array.ST.Iterator
- Data.Array.ST.Partial
- Data.Bifoldable
- Data.Bifunctor
- Data.Bifunctor.Clown
- Data.Bifunctor.Flip
- Data.Bifunctor.Join
- Data.Bifunctor.Joker
- Data.Bifunctor.Product
- Data.Bifunctor.Wrap
- Data.Bitraversable
- Data.Boolean
- Data.BooleanAlgebra
- Data.Bounded
- Data.Char
- Data.Char.Gen
- Data.Char.Utils
- Data.CommutativeRing
- Data.Distributive
- Data.DivisionRing
- Data.Either
- Data.Either.Inject
- Data.Either.Nested
- Data.Enum
- Data.Enum.Gen
- Data.Eq
- Data.EuclideanRing
- Data.Field
- Data.Foldable
- Data.FoldableWithIndex
- Data.Function
- Data.Function.Uncurried
- Data.Functor
- Data.Functor.Invariant
- Data.FunctorWithIndex
- Data.HeytingAlgebra
- Data.Identity
- Data.Int
- Data.Int.Bits
- Data.Maybe
- Data.Maybe.First
- Data.Maybe.Last
- Data.Monoid
- Data.Monoid.Additive
- Data.Monoid.Alternate
- Data.Monoid.Conj
- Data.Monoid.Disj
- Data.Monoid.Dual
- Data.Monoid.Endo
- Data.Monoid.Multiplicative
- Data.NaturalTransformation
- Data.Newtype
- Data.NonEmpty
- Data.Ord
- Data.Ord.Down
- Data.Ord.Max
- Data.Ord.Min
- Data.Ord.Unsafe
- Data.Ordering
- Data.Ring
- Data.Semigroup
- Data.Semigroup.First
- Data.Semigroup.Foldable
- Data.Semigroup.Last
- Data.Semigroup.Traversable
- Data.Semiring
- Data.Show
- Data.String
- Data.String.CaseInsensitive
- Data.String.CodePoints
- Data.String.CodeUnits
- Data.String.Common
- Data.String.Gen
- Data.String.NonEmpty
- Data.String.NonEmpty.CaseInsensitive
- Data.String.NonEmpty.CodePoints
- Data.String.NonEmpty.CodeUnits
- Data.String.NonEmpty.Internal
- Data.String.Pattern
- Data.String.Regex
- Data.String.Regex.Flags
- Data.String.Regex.Unsafe
- Data.String.Unsafe
- Data.String.Utils
- Data.Symbol
- Data.Traversable
- Data.Traversable.Accum
- Data.Traversable.Accum.Internal
- Data.TraversableWithIndex
- Data.Tuple
- Data.Tuple.Nested
- Data.Unfoldable
- Data.Unfoldable1
- Data.Unit
- Data.Void
- Effect
- Effect.Class
- Effect.Class.Console
- Effect.Console
- Effect.Ref
- Effect.Uncurried
- Effect.Unsafe
- Global
- Global.Unsafe
- MCPrelude
- Main
- Math
- PSCI.Support
- Partial
- Partial.Unsafe
- Prelude
- Prim
- Prim.Boolean
- Prim.Ordering
- Prim.Row
- Prim.RowList
- Prim.Symbol
- Prim.TypeError
- Record.Unsafe
- Type.Data.Row
- Type.Data.RowList
- Type.Equality
- Unsafe.Coerce