valderman / haste-compiler

A GHC-based Haskell to JavaScript compiler
http://haste-lang.org
BSD 3-Clause "New" or "Revised" License
1.45k stars 109 forks source link

Question: Does haste support passing (variadic) callbacks to javascript? #393

Closed crocket closed 7 years ago

crocket commented 7 years ago

A while ago, to ghcjs-base project, I submitted a pull request that adds variadic callback generators. You can read the details on https://github.com/crocket/ghcjs-base#callbacks-with-arbitrary-numbers-of-arguments.

Haste seems similar to GHCJS, and I wonder whether I can do the same with Haste.

valderman commented 7 years ago

Haste supports passing callbacks through the Haste.Foreign FFI:

{-# LANGUAGE OverloadedStrings #-}
import Haste.Foreign

withPrompt :: (String -> IO ()) -> IO ()
withPrompt = ffi "(function(f){f(prompt('Name, please!'));})"

main = withPrompt $ \name -> putStrLn ("Hello, " ++ name)

While it doesn't support functions which are actually variadic (i.e. may be called with a different number of arguments each time), you can easily fake it using Maybe arguments (currently only in 0.6 dev branch; 0.5.x doesn't consider undefined to be Nothing for marshalling purposes):

{-# LANGUAGE OverloadedStrings #-}
import Haste.Foreign

withPrompt :: (Maybe String -> IO ()) -> IO ()
withPrompt = ffi "(function(f){f();})"

main = withPrompt $ \mname -> do
  case mname of
    Just name -> putStrLn ("Hello, " ++ name)
    _         -> putStrLn "No name. :("

This paper describes the FFI in detail. There isn't a lot of user-oriented documentation for the FFI in particular, but this example shows the basics through a very minimal jQuery example.

crocket commented 7 years ago

It seems Haste FFI overlaps to some degree with GHCJS FFI and ghcjs-base.

I mixed arguments object with a variadic function to create variadic callback generators. They do not create variadic callbacks, but they can create any kind of callback. The variadic function merely maps haskell arguments to arguments object.

If it was possible to convert a haskell function to a javascript function, the same trick as I used in ghcjs-base could be used. Can a haskell function be converted to a javascript function in Haste with ease? In other words, is there a clean way to turn a haskell function into JSAny?

valderman commented 7 years ago

With Haste any Haskell function can be used as a callback, without having to call an explicit generator for it. If you want to do that anyway for some reason, you can just use the ToAny instance for marshallable functions: some_callback = toAny $ \x y z -> putStrLn (concat [x, y, z]).

As far as I understand, your variadic generator essentially allows the same thing but for the JSFFI, which is more restrictive about what values can be marshalled? If I'm mistaken here, could you give an example of a Haste program that would benefit from having this construction, to help me understand the idea a bit better?

Apologies for the late reply; things have been a bit hectic of late.

crocket commented 7 years ago

If any haskell function can be used as a callback in haste, then haste doesn't need my callback generator. GHCJS FFI is not very good.