我有以下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
。
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
,而是Effect
。
因此,为了修复你的FFI,你只需要插入一个额外的无参数函数,它将为返回的exports.parseFromString = function (documentType) {
return function (sourceString) {
return function (domParser) {
return function() {
return domParser.parseFromString(sourceString, documentType);
}
};
};
};
建模:
makeDOMParser :: Effect DOMParser
(值得注意的是,EffectFn1
, runEffectFn1
, and friends在您的FFI模块中被正确建模为无参数函数)
但还有更好的方法
这些JS中嵌套函数的金字塔确实看起来很难看,你必须同意。因此,有一个应用程序 - EffectFnX
毫不奇怪。这些是简单的包装器,它们将JavaScript样式的函数“(即将所有参数一次性”)“转换”为PureScript风格的curried有效函数(即逐个获取参数并返回效果)。
您可以将JS方面声明为普通的JS函数,然后将其作为runEffectFnX
导入PureScript,并在需要时使用// 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
调用它:
EffectFn1
附:购买Fn1
and friends的人也喜欢qazxswpoi - 同样的事情,但是对于纯粹的(无效的)功能。