为什么这个函数应用程序在纯脚本中会产生运行时错误?
Why does this function application generate a runtime error in purescript?
我有以下 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 中的建模方式:有效计算不是一个值,而是一个值的“承诺”,您可以评估该值并获得该值作为结果。一个值的“承诺”可以被建模为一个函数,该函数 return 是一个值,这正是它在 PureScript 中的建模方式。
例如,这个:
a :: Effect Unit
编译为 JavaScript 为:
function a() { return {}; }
同样,这个:
f :: String -> Effect Unit
编译为 JavaScript 为:
function f(s) { return function() { return {}; } }
所以它接受一个字符串作为参数,然后returns 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
- 即它接受三个参数,一个接一个,并且 return 是一个已解析的文档。
但是在 PureScript 方面,您将其定义为 parseFromString :: String -> String -> DOMParser -> Effect Document
- 这意味着它应该采用三个参数,一个接一个,然后是 return 一个 Effect Document
- 这如上所述,应该是一个无参数函数。当您尝试评估 Effect Unit
时,正是这个额外的无参数调用失败了,实际上它根本不是 Effect
,而是 Document
.
所以,为了修复你的 FFI,你只需要插入一个额外的无参数函数,它将模拟 returned 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 风格的柯里化有效函数(即一个接一个地获取参数并 returning 效果)的包装器。
您可以将 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 - 同样的东西,但用于纯(非有效)功能。
我有以下 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 中的建模方式:有效计算不是一个值,而是一个值的“承诺”,您可以评估该值并获得该值作为结果。一个值的“承诺”可以被建模为一个函数,该函数 return 是一个值,这正是它在 PureScript 中的建模方式。
例如,这个:
a :: Effect Unit
编译为 JavaScript 为:
function a() { return {}; }
同样,这个:
f :: String -> Effect Unit
编译为 JavaScript 为:
function f(s) { return function() { return {}; } }
所以它接受一个字符串作为参数,然后returns 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
- 即它接受三个参数,一个接一个,并且 return 是一个已解析的文档。
但是在 PureScript 方面,您将其定义为 parseFromString :: String -> String -> DOMParser -> Effect Document
- 这意味着它应该采用三个参数,一个接一个,然后是 return 一个 Effect Document
- 这如上所述,应该是一个无参数函数。当您尝试评估 Effect Unit
时,正是这个额外的无参数调用失败了,实际上它根本不是 Effect
,而是 Document
.
所以,为了修复你的 FFI,你只需要插入一个额外的无参数函数,它将模拟 returned 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 风格的柯里化有效函数(即一个接一个地获取参数并 returning 效果)的包装器。
您可以将 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 - 同样的东西,但用于纯(非有效)功能。