我有以下PureScript片段;注意parseXMLFromString
被部分应用:
parseXMLFromString ∷ String → DOMParser → Effect Document
parseXMLFromString s d =
parseFromString "application/xml" s d
parseNoteDoc :: DOMParser -> Effect Document
parseNoteDoc = parseXMLFromString TD.noteXml
note <- parseNoteDoc domParser
将生成以下代码:
// Generated by purs version 0.12.4
"use strict";
var Effect_Console = require("../Effect.Console/index.js");
var Test_Data = require("../Test.Data/index.js");
var Web_DOM_DOMParser = require("../Web.DOM.DOMParser/index.js");
var parseNoteDoc = Web_DOM_DOMParser.parseXMLFromString(Test_Data.noteXml);
var main = function __do() {
var v = Web_DOM_DOMParser.makeDOMParser();
var v1 = parseNoteDoc(v)();
return Effect_Console.log("TODO: You should add some tests.")();
};
module.exports = {
parseNoteDoc: parseNoteDoc,
main: main
};
第var v1 = parseNoteDoc(v)();
行给出了错误TypeError: parseNoteDoc(...) is not a function
。
我不确定()
上多余的parseNoteDoc
来自哪里,但这就是问题所在。当我在生成的源中手动删除()
时,它可以按预期工作。
更新:添加了用于在this branch上重现此代码的代码。完成通常的手续后,npm run testbrowser
并在浏览器中打开dist/index.html
。
答案 0 :(得分:2)
TL; DR:您的FFI代码不正确,您需要添加额外的function()
。
详细说明:
多余的空括号来自Effect
。
这是在PureScript中建模有效计算的方式:有效计算不是值,而是值的“承诺”,您可以评估并获得结果。值的“承诺”可以建模为返回值的函数,而这正是在PureScript中建模的方式。
例如,此:
a :: Effect Unit
编译为JavaScript的方式是:
function a() { return {}; }
与此类似,
f :: String -> Effect Unit
编译为JavaScript的方式是:
function f(s) { return function() { return {}; } }
因此,它将字符串作为参数,然后返回Effect Unit
,它本身就是JS中的无参数函数。
但是,在您的FFI module中,您将parseFromString
定义为:
exports.parseFromString = function (documentType) {
return function (sourceString) {
return function (domParser) {
return domParser.parseFromString(sourceString, documentType);
};
};
};
与parseFromString :: String -> String -> DOMParser -> Document
等效-即,它采用三个参数,一个接一个,然后返回已解析的文档。
但是在PureScript方面,您将其定义为parseFromString :: String -> String -> DOMParser -> Effect Document
-这意味着它应该一个接一个地接受三个参数,然后返回一个Effect Document
-如上所述,它应该是,无参数函数。正是这种额外的无参数调用在尝试评估Effect Unit
时失败,而实际上它根本不是Effect
,而是Document
。
因此,为了修复您的FFI,您只需要插入一个额外的无参数函数即可对返回的Effect
进行建模:
exports.parseFromString = function (documentType) {
return function (sourceString) {
return function (domParser) {
return function() {
return domParser.parseFromString(sourceString, documentType);
}
};
};
};
(有趣的是,makeDOMParser :: Effect DOMParser
在FFI模块中已正确建模为无参数函数)
但是有更好的方法
这些JS中嵌套函数的金字塔看起来确实很难看,您必须同意。因此,为此而准备的应用程序-EffectFn1
, runEffectFn1
, and friends也就不足为奇了。这些是简单的包装器,可将JavaScript样式的函数(即一次获取所有参数)“转换”为PureScript样式的有效函数(即一个一地获取参数并返回效果)。
您可以将JS端声明为普通的JS函数,然后将其作为EffectFnX
导入PureScript,并在需要时使用runEffectFnX
进行调用:
// JavaScript:
exports.parseFromString = function (documentType, sourceString, domParser) {
return domParser.parseFromString(sourceString, documentType);
};
-- PureScript:
foreign import parseFromString ∷ EffectFn3 String String DOMParser Document
parseHTMLFromString ∷ String → DOMParser → Effect Document
parseHTMLFromString s d =
runEffectFn3 parseFromString "text/html" s d
P.S。购买EffectFn1
的人也喜欢Fn1
and friends-一样,只是功能纯(无效)。