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 как 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
P.S. Людям, которые приобрели EffectFn1
, также понравились Fn1
и друзья - то же самое, но для чистых (неэффективных) функций.