我正在尝试将 mocha 绑定(bind)写入 PureScript 并完全被 Control.Monad.Eff 困惑

describe(function(){
  //do stuff
});

Describe 是一个不带任何东西并返回 IO 或 Eff 或其他意思的函数(副作用发生没有返回值)。

我到目前为止的尝试
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

显然这里缺少一些东西。请帮忙。

最佳答案

PureScript 的外部函数接口(interface)其实很简单。例如,假设您有以下 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 monad。相反,它使用 Eff monad。

据我所知,Eff monad 与 IO monad 相同,但有一个额外的类型参数:一行效果。

例如,在 Haskell 中,print 函数具有以下类型:
print :: Show a => a -> IO ()

在 PureScript 中,print 函数具有以下类型:
print :: Show a => a -> Eff (trace :: Trace | r) Unit

那么我们从中可以理解什么呢?
  • IOEff e 类似,其中 e 是一排效果。
  • Unit 类似于 ()
  • print 函数具有 trace 效果,其类型为 Trace
  • 此外,print 函数可以与其他效果结合使用。行多态性。这意味着它是可组合的。

  • 一个 Eff 值本身被称为一个 Action 。例如,类型为 print "Hello World!"Eff (trace :: Trace | r) Unit 是一个 Action 。

    作为函数参数的 Eff 值称为处理程序。它可以被认为是一个没有参数的高阶有效函数。

    没有副作用的 Eff 值被称为纯值:
    type Pure a = forall e. Eff e a
    runPure :: Pure a -> a
    

    由于效果行(即 e )是多态的(或者换句话说,是一个黑洞),PureScript 假设该函数没有副作用。然而,这也意味着它可以与其他有效的功能组合。
    Eff monad 是程序员和编译器之间的契约,其中程序员向编译器 promise 给定的 Eff 值将仅具有规定的效果行,而没有更多。

    来到你的 describe 函数:



    其实这是错误的。您的 describe 函数确实将函数作为参数:
    describe(function(){
      //do stuff
    });
    

    另外它所接受的函数没有参数,这意味着它是一个有效的函数。因此它必须是 Eff e a 类型,其中 ea 可以分别是任何效果行和任何返回值。

    因此,您的 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
        };
    }());
    

    希望有帮助。

    关于mocha.js - PureScript FFI 转 Mocha ,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24728624/

    10-13 09:11