Вот способ заставить это работать. Предположим, у нас есть какая-то полезная функция, например
revString :: String -> String
revString = reverse
somethingUseful :: JSString -> IO JSString
somethingUseful = return . toJSString . revString . fromJSString
Чтобы экспортировать это, нам нужно сделать обратный вызов с помощью одной из функций *Callback
в GHCJS.Foreign
. Но они отбрасывают возвращаемое значение, поэтому нам нужна оболочка, которая помещает результат во второй аргумент:
returnViaArgument :: (JSRef a -> IO (JSRef b)) -> JSRef a -> JSRef c -> IO ()
returnViaArgument f arg retObj = do
r <- f arg
setProp "ret" r retObj
Моя функция main
создает обратный вызов и сохраняет его как нечто глобальное для JavaScript:
foreign import javascript unsafe "somethingUseful_ = $1"
js_set_somethingUseful :: JSFun a -> IO ()
main = do
callback <- syncCallback2 NeverRetain False (returnViaArgument somethingUseful)
js_set_somethingUseful callback
Наконец, нам нужна небольшая распаковка на стороне JS:
function somethingUseful (arg) {x = {}; somethingUseful_(arg, x); return x.ret};
и теперь мы можем использовать нашу прекрасную функцию, реализованную на Haskell:
somethingUseful("Hello World!")
"!dlroW olleH"
Я использую этот трюк в реальном приложении. В JsInterface.hs, который определен как main-in
из executable
в Cabal-файле функция main
устанавливает глобальная переменная java-скрипта incredibleLogic_
, а клей JavaScript code заботится об упаковке и распаковке параметров.
person
Joachim Breitner
schedule
24.07.2015
var haskell = {}, export = functon (name, val) { haskell[name] = val; };
, а затем вы переноситеexport
в Haskell через FFI,export "sayHello" sayHello
потенциально должен установитьhaskell.sayHello
на любую функцию, без странных переменныхh$main()
, засоряющих все вокруг. - person CR Drost   schedule 30.04.2015