PureScript FFI到摩卡

Fre*_*all 12 ffi mocha.js purescript

我试图将mocha绑定写入PureScript,我完全不知所措 Control.Monad.Eff

describe(function(){
  //do stuff  
});
Run Code Online (Sandbox Code Playgroud)

描述是一个不带任何东西并返回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
Run Code Online (Sandbox Code Playgroud)

显然遗漏了一些东西.请帮忙.

Aad*_*hah 14

PureScript的外部函数接口实际上非常简单.例如,假设您具有以下JavaScript函数:

function si(p) {
    return function (r) {
        return function (t) {
            return p * r * t / 100;
        };
    };
}
Run Code Online (Sandbox Code Playgroud)

您可以按如下方式导入它:

foreign import si :: Number -> Number -> Number -> Number
Run Code Online (Sandbox Code Playgroud)

您还可以按如下方式内联函数:

foreign import si
    "function si(p) {\
    \    return function (r) {\
    \        return function (t) {\
    \            return p * r * t / 100;\
    \        };\
    \    };\
    \}" :: Number -> Number -> Number -> Number
Run Code Online (Sandbox Code Playgroud)

对于副作用,PureScript不使用IOmonad.相反,它使用Effmonad.

根据我的理解,Effmonad IO与具有额外类型参数的monad 相同:一行效果.

例如,在Haskell中,该print函数具有以下类型:

print :: Show a => a -> IO ()
Run Code Online (Sandbox Code Playgroud)

在PureScript中,该print函数具有以下类型:

print :: Show a => a -> Eff (trace :: Trace | r) Unit
Run Code Online (Sandbox Code Playgroud)

那么我们从中得到什么呢?

  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
Run Code Online (Sandbox Code Playgroud)

由于效果行(即e)是多态的(或者换句话说是空的,黑洞),PureScript假定该函数没有副作用.然而,这也意味着它可以与其他有效的功能组合.

Eff单子是程序员,在程序员承诺编译器给定的编译器之间的合同Eff价值将只影响既定的行并没有更多的.


来你的describe功能:

描述是一个不带任何东西并返回IO,或Eff或其他东西的函数(副作用没有返回值).

其实这是错的.您的describe函数确实将函数作为参数:

describe(function(){
  //do stuff
});
Run Code Online (Sandbox Code Playgroud)

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

因此,您的describe函数必须是以下类型:

describe :: Eff e a -> Eff (describe :: Describe | e) {}
Run Code Online (Sandbox Code Playgroud)

在Haskell中,它将写成如下:

describe :: IO a -> IO ()
Run Code Online (Sandbox Code Playgroud)

PureScript比Haskell更明确.无论如何,Describe是您创建的新效果类型,它将其与其他效果类型区分开来,例如Trace:

foreign import data Describe :: !
Run Code Online (Sandbox Code Playgroud)

然后,您将导入describe如下:

foreign import describe
    "function describe(f) {\
    \    return function () {\
    \        window.describe(f);\
    \    };\
    \}" :: forall e a. Eff e a -> Eff (describe :: Describe | e) {}
Run Code Online (Sandbox Code Playgroud)

最后你可以使用它如下:

main = do
    describe $ print "Hello World!"
Run Code Online (Sandbox Code Playgroud)

整个代码如下:

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!"
Run Code Online (Sandbox Code Playgroud)

它会产生以下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
    };
}());
Run Code Online (Sandbox Code Playgroud)

希望有所帮助.

  • 类型`forall e.{a :: A,b :: B | e}`表示"匹配一个具有属性`a :: A`和`b :: B`,__和任何其他属性___的对象".这是必要的,因为对象可能具有其他属性.如果我们只编写`{a :: A,b :: B}`那么编译器会认为该对象只有属性`a :: A`和`b :: B`而没有别的.这意味着如果对象具有其他属性,则编译器将抛出错误.添加额外的`| 最后的e`告诉编译器对象有其他属性是可以的.还可以合并对象. (4认同)
  • Haskell中的`forall`是隐式的,这意味着您不需要键入它.因此,在Haskell中,如果键入`foldl ::(a - > b - > a) - > a - > [b] - > a`,编译器会认为它意味着`foldl :: forall a b.(a - > b - > a) - > a - > [b] - > a`.但是在PureScript中,`forall`是显式的,这意味着你总是要输入它,否则编译器会产生错误.这很难看,但还是可以的. (3认同)
  • 'Eff` monad的亲切签名是`Eff ::#! - >* - >*`.这意味着第一个参数是__effects __的__row __(用`#`表示)(用`!`表示).第二个参数是任何纯(即无效)值(用`*`表示).结果也是纯粹的价值.因此,`Eff` monad需要两个参数:一行效果类型和一个返回类型.你的`describe`函数的类型是`Eff ea - > Eff(describe :: Describe | e){}`.这意味着参数可以具有任意数量的效果并返回任何值.返回类型添加新效果并返回空对象值 (3认同)