PureScript的外部函数接口实际上非常简单。例如,假设您有以下JavaScript函数:
function si(p) {
return function (r) {
return function (t) {
return p * r * t / 100;
};
};
}
您可以按照以下方式导入它:
foreign import si :: Number -> Number -> Number -> Number
您也可以将函数内联,如下所示:
您也可以将函数内联,如下所示:
foreign import si
"function si(p) {\
\ return function (r) {\
\ return function (t) {\
\ return p * r * t / 100;\
\ };\
\ };\
\}" :: Number -> Number -> Number -> Number
对于副作用,PureScript不使用IO
单子。相反,它使用了Eff
单子。
据我所知,Eff
单子与IO
单子相同,只是额外有一个类型参数:一行效果。
例如,在Haskell中,print
函数的类型如下:
print :: Show a => a -> IO ()
在 PureScript 中,
print
函数的类型如下:
print :: Show a => a -> Eff (trace :: Trace | r) Unit
那么我们从中可以得出什么结论呢?
1. `IO` 类似于 `Eff e`,其中 `e` 是一个效果行。
2. `Unit` 类似于 `()`。
3. `print` 函数具有 `trace` 效果,其类型为 `Trace`。
4. 此外,`print` 函数可以与其他效果组合。这意味着它是可组合的。行多态。
一个单独的 `Eff` 值被称为一个动作。例如,`print "Hello World!"` 的类型为 `Eff (trace :: Trace | r) Unit`,是一个动作。
作为函数参数的 `Eff` 值被称为处理程序。它可以被看作是一个没有参数的高阶效应函数。
没有副作用的 `Eff` 值被称为纯值。
type Pure a = forall e. Eff e a
runPure :: Pure a -> a
由于效果(即
e
)的行是多态的(换句话说,是空的,一个黑洞),PureScript会认为该函数没有副作用。然而,这也意味着它可以与其他具有影响力的函数组合使用。
Eff
monad是程序员与编译器之间的契约,程序员承诺给定的
Eff
值只有陈述的效果行,没有更多。
来到你的
describe
函数:
Describe
是一个不带参数并返回IO、Eff或其他意义上的函数(发生了副作用但未返回任何值)。
实际上这是错误的,你的
describe
函数确实需要一个函数作为参数:
describe(function(){
});
此外,它所接受的函数没有参数,这意味着它是一个有副作用的函数。因此,它必须是类型为 Eff e a
的函数,其中 e
和 a
分别可以是任何效果行和任何返回值。
因此,您的 describe 函数必须是以下类型:
describe :: Eff e a -> Eff (describe :: Describe | e) {}
在 Haskell 中,它将被写成以下形式:
describe :: IO a -> IO ()
PureScript只是比Haskell更加明确。无论如何,
Describe
是一个新的效应类型,你需要创建它来区别于其他效应类型如
Trace
:
foreign import data Describe :: !
您需要按照以下方式导入
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!"
整个代码如下:
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!"
它将生成以下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
};
}());
希望能对您有所帮助。