It is true that all provided examples (runGcd
, runGcdUncurried
, alert
, uncurriedAlert
) can be called functions from JS perspective. On the other hand PureScript separates pure functions from āeffectsā (side effecting computations) so let me split this answer into two sections.
Uncurried pure JS functions
Data.Function.Uncurried
I think that PureScript by itself doesnāt provide the notion of the uncurried function like we know it from the languages like JS. All functions have one argument. Even when you use uncurry
you get back a function which takes a single argument - a Tuple
.
If you really want to write type signature for an uncurried JS function and use it through FFI there is a dedicated module in purescript-functions Data.Function.Uncurried for this purpose.
Debugging and examples
runGcdUncurried
Now letās try to understand what is going on when you are running your gcd
related examples. There are few surprises there and this is really expected - we are dealing with untyped JS code here - using FFI is a dangerous path to takeā¦
You are trying to use compiled PureScript function Test.Gcd.gcd
(gcd ā· Int ā Int ā Int
). If you take a look at the output of the Test.Gcd
module you can find that this function is compiled into a function which returns a function which returns an Int
value:
var gcd = function ($copy_v) {
return function ($copy_v1) {
// actual body of the function
// ...
return $tco_result;
}
}
In your FFI you are calling this function in uncurried js manner gcd(n, m)
. I think that you should use this arguments in two separate calls like gcd(n)(m)
.
You have provided uncurried runGcdUncurried
in your FFI. But you gave it a curried type on the PureScript side:
exports.runGcdUncurried = function(n, m) {
// This is incorrect usage of gcd :-)
return Tg.gcd(n, m);
};
foreign import runGcdUncurried ā· Int ā Int ā Int
So finally when you applied it to the two Int
values runGcdUncurried 15 20
compiler was happy because this is an expected usage of a function with this type. What is even more interesting it worked becauseā¦ runGcdUncurried
called the original gcd
function like Tg.gcd(15, undefined)
because m
was not provided from PS side. This gcd
call returned a function which expects another Int
which was applied by the compiler and everything finished succesfully.
We got something like Tg.gcd(15, undefined)(20)
call at the end.
If you really want to provide a type for this uncurried function you should probably use Fn2
from the lib and run it with runFn2
:
exports.runGcdUncurried = function(n, m) {
// We are using here curried `gcd` function so we need two execute two calls.
return Tg.gcd(n)(m);
};
foreign import runGcdUncurried ā· Fn2 Int Int Int
log $ show $ runFn2 runGcdUncurried 15 20
runGcd
Now letās take a look at runGcd
function. You have typed it as crurried function runGcd ā· Int ā Int ā Int
but there are two problems with the current FFI implementation:
exports.runGcd = function(n) {
return function(m) {
return function() {
return Tg.gcd(n, m);
};
};
};
There is additional function()
wrapper which is not reflected in the type. If we try to simplify and drop this empty function and use gcd
as uncurried function we are going to get a working version:
exports.runGcdFix = function(n) {
return function(m) {
return Tg.gcd(n)(m);
};
};
TBC