purescript - 为什么这个函数应用程序会在 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
但这就是问题所在。当我()
在生成的源中手动删除时,它按预期工作。
更新:添加了在此分支上重现此代码的代码。照常办理手续后,在浏览器中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 模块中,您定义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
, 和朋友。这些是简单的包装器,可以将 JavaScript 风格的函数(即一次获取所有参数)“转换”为 PureScript 风格的柯里化有效函数(即一个一个地获取参数并返回效果)。
你可以将你的 JS 端声明为一个普通的 JS 函数,然后将其导入 PureScript as ,并在需要的地方EffectFnX
调用它: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
PS购买的人EffectFn1
也喜欢Fn1
和朋友-同样的事情,但对于纯粹(无效)的功能。
推荐阅读
- discord.js - 如何获取机器人所在的每个公会中所有成员的成员数
- datetime - 在日历中选择日期并在 tkinter 上更改其格式
- python - 检查所有唯一条目的最小值
- sql - 如果小于配置的参数,Oracle SQL 分配
- spring-boot - AWS Lambda 中的 DTO 验证
- javascript - 从用户控件运行时,asp modal 弹出窗口会立即关闭
- java - 在 JAVA 代码的不同部分中多次使用数组列表
- java - 使用 Graphics2D,当我拖动形状时,我想移动形状
- c# - 当接收到过多的传递字段时,传递给控制器的模型变为空
- python-3.x - 如何在自定义 dataproc 映像中安装可选组件(anaconda、jupyter)