I am trying to write mocha bindings into PureScript and am completely baffled by Control.Monad.Eff
describe(function(){
//do stuff
});
Describe is a function that takes nothing and returns IO, or Eff or something that means (side-effect happened no value returned).
My attempts so far
foreign import describe
"function describe(n){ \
\ return function(){ \
\ window.describe(n); \
\ }; \
\}" :: forall eff a. Eff eff a -> Eff eff
foreign import describe "describe" :: forall eff a. Eff eff a -> Eff eff
foreign import describe "describe" :: Eff -> Eff
foreign import describe "describe" :: forall eff a. (a -> Eff eff) -> Eff eff
Clearly missing something here. Please help.
The foreign function interface of PureScript is actually very simple. For example suppose you have the following JavaScript function:
function si(p) {
return function (r) {
return function (t) {
return p * r * t / 100;
};
};
}
You could import it as follows:
foreign import si :: Number -> Number -> Number -> Number
You could also inline the function as follows:
foreign import si
"function si(p) {\
\ return function (r) {\
\ return function (t) {\
\ return p * r * t / 100;\
\ };\
\ };\
\}" :: Number -> Number -> Number -> Number
For side effects PureScript doesn't use the IO
monad. Instead it makes use of the Eff
monad.
From what I understand the Eff
monad is the same as the IO
monad with an extra type parameter: a row of effects.
For example, in Haskell the print
function has the following type:
print :: Show a => a -> IO ()
In PureScript the print
function has the following type:
print :: Show a => a -> Eff (trace :: Trace | r) Unit
So what do we understand from this?
IO
is similar to Eff e
where e
is a row of effects.Unit
is similar to ()
.print
function has the trace
effect which is of the type Trace
.print
function can be combined with an other effect. Row polymorphism. This means that it is composable.An Eff
value by itself is called an action. For example print "Hello World!"
which is of the type Eff (trace :: Trace | r) Unit
is an action.
An Eff
value which is an argument to a function is called a handler. It can be thought of as a higher-order effectful function with no parameters.
An Eff
value with no side-effects is known as a pure value:
type Pure a = forall e. Eff e a
runPure :: Pure a -> a
Since the row of effects (i.e. e
) is polymorphic (or in other words empty, a black hole), PureScript assumes that the function has no side-effects. However it also means that it can be composed with other effectful functions.
The Eff
monad is a contract between the programmer and the compiler in which the programmer promises the compiler that the given Eff
value will only have the stated row of effects and no more.
Coming to your describe
function:
Describe is a function that takes nothing and returns IO, or Eff or something that means (side-effect happened no value returned).
Actually this is wrong. Your describe
function does take a function as an argument:
describe(function(){
//do stuff
});
In addition the function that it takes has no arguments, which means that it is an effectful function. Hence it must be of the type Eff e a
where e
and a
can be any row of effects and any return value respectively.
Thus your describe function must be of the type:
describe :: Eff e a -> Eff (describe :: Describe | e) {}
In Haskell it would be written as follows:
describe :: IO a -> IO ()
PureScript is just more explicit than Haskell. Anyway, Describe
is a new effect type that you create which distinguishes it from other effect types such as Trace
:
foreign import data Describe :: !
You would then import describe
as follows:
foreign import describe
"function describe(f) {\
\ return function () {\
\ window.describe(f);\
\ };\
\}" :: forall e a. Eff e a -> Eff (describe :: Describe | e) {}
Finally you can use it as follows:
main = do
describe $ print "Hello World!"
The entire code is as follows:
module Main where
import Control.Monad.Eff
import Debug.Trace
foreign import data Describe :: !
foreign import describe
"function describe(f) {\
\ return function () {\
\ window.describe(f);\
\ };\
\}" :: forall e a. Eff e a -> Eff (describe :: Describe | e) {}
main = do
describe $ print "Hello World!"
It would produce the following JavaScript:
var PS = PS || {};
PS.Main = (function () {
"use strict";
var Prelude = PS.Prelude;
var Debug_Trace = PS.Debug_Trace;
function describe(f) {
return function () {
window.describe(f);
};
}
var print = Debug_Trace.print(Prelude.showString({}));
var main = describe(print("Hello World!"));
return {
main: main,
describe: describe
};
}());
Hope that helps.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With