23

私はGHCJSで遊んでいます。FFI を使用して Haskell から JavaScript を呼び出すことができますが、その逆の方法がわかりません。Haskell で書いた非常に便利なユーティリティ関数があるとします。

sayHello :: String -> IO ()
sayHello name = print $ "hello, " ++ name

Javascriptから呼び出すことができるように何かをすることは可能ですか? h$main(h$main2CMainzimain)最も近いのは、Haskell のメイン関数をトリガーすることに気付くことです。

4

2 に答える 2

11

これを機能させる方法を次に示します。次のような便利な関数があるとします。

revString :: String -> String
revString = reverse

somethingUseful :: JSString -> IO JSString
somethingUseful = return . toJSString . revString  . fromJSString

*Callbackそれをエクスポートするには、 の関数の 1 つを介してコールバックにする必要がありますGHCJS.Foreign。ただし、これらは戻り値を破棄するため、結果を 2 番目の引数に入れるラッパーが必要です。

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"

私はこのトリックを実際のアプリケーションで使用しています。Cabal ファイルの時点で定義されているJsInterface.hsでは、関数がグローバル Java スクリプト変数を設定し、JavaScript グルー コードがパラメーターのパックとアンパックを処理します。main-inexecutablemainincredibleLogic_

于 2015-07-24T13:05:31.520 に答える
10

Javascript から Haskell 関数を呼び出す方法を示す例を次に示します。これは Joachim によって提供された例に似ていますが、最新の ghcjs でコンパイルおよび実行されます。

import GHCJS.Marshal(fromJSVal)
import GHCJS.Foreign.Callback (Callback, syncCallback1, OnBlocked(ContinueAsync))
import Data.JSString (JSString, unpack, pack)
import GHCJS.Types (JSVal)

sayHello :: String -> IO ()
sayHello name = print $ "hello, " ++ name

sayHello' :: JSVal -> IO ()
sayHello' jsval = do
    Just str <- fromJSVal jsval
    sayHello $ unpack str

foreign import javascript unsafe "js_callback_ = $1"
    set_callback :: Callback a -> IO ()

foreign import javascript unsafe "js_callback_($1)" 
    test_callback :: JSString -> IO ()

main = do
    callback <- syncCallback1 ContinueAsync sayHello'
    set_callback callback
    test_callback $ pack "world"

このテストは、Haskell から Javascript コードを呼び出し、それから Haskell にコールバックすることによって機能します。変数「js_callback_」は、1 つの文字列引数を取る関数として Javascript 内で使用できるようになります。

于 2015-12-18T03:14:42.763 に答える