Ответ 1
Внешний интерфейс PureScript на самом деле очень прост. Например, предположим, что у вас есть следующая функция JavaScript:
function si(p) {
return function (r) {
return function (t) {
return p * r * t / 100;
};
};
}
Вы можете импортировать его следующим образом:
foreign import si :: Number -> Number -> Number -> Number
Вы также можете включить функцию следующим образом:
foreign import si
"function si(p) {\
\ return function (r) {\
\ return function (t) {\
\ return p * r * t / 100;\
\ };\
\ };\
\}" :: Number -> Number -> Number -> Number
Для побочных эффектов PureScript не использует монаду IO
. Вместо этого он использует монаду Eff
.
Из того, что я понимаю, монада Eff
такая же, как монада IO
с дополнительным параметром типа: ряд эффектов.
Например, в Haskell функция print
имеет следующий тип:
print :: Show a => a -> IO ()
В PureScript функция print
имеет следующий тип:
print :: Show a => a -> Eff (trace :: Trace | r) Unit
Итак, что мы понимаем из этого?
-
IO
похож наEff e
, гдеe
представляет собой ряд эффектов. -
Unit
похож на()
. - Функция
print
имеет эффектtrace
, который имеет типtrace
. - Кроме того, функция
print
может быть объединена с другим эффектом. Полиморфизм строк. Это означает, что он является составным.
Значение An Eff
само по себе называется действием. Например, print "Hello World!"
, который имеет тип Eff (trace :: Trace | r) Unit
, является действием.
Значение an Eff
, являющееся аргументом функции, называется обработчиком. Его можно рассматривать как эффективную функцию более высокого порядка без параметров.
Значение Eff
без побочных эффектов известно как чистое значение:
type Pure a = forall e. Eff e a
runPure :: Pure a -> a
Поскольку строка эффектов (т.е. e
) является полиморфной (или, другими словами, пустой, черной дырой), PureScript предполагает, что функция не имеет побочных эффектов. Однако это также означает, что он может быть скомбинирован с другими эффективными функциями.
Монада Eff
- это контракт между программистом и компилятором, в котором программист promises компилятор, что данное значение Eff
будет иметь только указанную строку эффектов и не более.
Переход к вашей функции describe
:
Опишите - это функция, которая ничего не принимает и возвращает IO, или Eff, или что-то, что означает (побочный эффект не возвращал значения).
На самом деле это неправильно. Ваша функция describe
принимает функцию в качестве аргумента:
describe(function(){
//do stuff
});
Кроме того, функция, которую он принимает, не имеет аргументов, что означает, что она является эффективной. Следовательно, он должен быть типа Eff e a
, где e
и a
может быть любой строкой эффектов и любым возвращаемым значением соответственно.
Таким образом, ваша описательная функция должна быть типа:
describe :: Eff e a -> Eff (describe :: Describe | e) {}
В Haskell это будет записано следующим образом:
describe :: IO a -> IO ()
PureScript является более явным, чем Haskell. В любом случае, describe
- это новый тип эффекта, который вы создаете, который отличает его от других типов эффектов, таких как trace
:
foreign import data Describe :: !
Затем вы импортируете describe
следующим образом:
foreign import describe
"function describe(f) {\
\ return function () {\
\ window.describe(f);\
\ };\
\}" :: forall e a. Eff e a -> Eff (describe :: Describe | e) {}
Наконец, вы можете использовать его следующим образом:
main = do
describe $ print "Hello World!"
Весь код выглядит следующим образом:
module Main where
import Control.Monad.Eff
import Debug.Trace
foreign import data Describe :: !
foreign import describe
"function describe(f) {\
\ return function () {\
\ window.describe(f);\
\ };\
\}" :: forall e a. Eff e a -> Eff (describe :: Describe | e) {}
main = do
describe $ print "Hello World!"
Он создаст следующий JavaScript:
var PS = PS || {};
PS.Main = (function () {
"use strict";
var Prelude = PS.Prelude;
var Debug_Trace = PS.Debug_Trace;
function describe(f) {
return function () {
window.describe(f);
};
}
var print = Debug_Trace.print(Prelude.showString({}));
var main = describe(print("Hello World!"));
return {
main: main,
describe: describe
};
}());
Надеюсь, что это поможет.