为什么这个函数应用程序在purescript中生成运行时错误?

问题描述 投票:1回答:1

我有以下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

purescript
1个回答
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,而是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 - 同样的事情,但是对于纯粹的(无效的)功能。

© www.soinside.com 2019 - 2024. All rights reserved.