Last active
December 25, 2015 05:29
-
-
Save chreekat/6924735 to your computer and use it in GitHub Desktop.
Fay FFI Hello World / Tutorial
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| {-# LANGUAGE EmptyDataDecls #-} | |
| -- This is a literate file, for some value of 'literate'. | |
| -- | |
| -- Read the comments. Read the code. Enjoy. :) | |
| import Prelude | |
| import FFI | |
| -- | Meme-appropriate starting point. We use javascript to make fay which | |
| -- makes javascript! | |
| hw1 :: Fay () | |
| hw1 = ffi "window.addEventListener('load', function () { alert('Hello, world!'); })" | |
| -- Let's try harder. Let's abstract out some types and APIs. We have | |
| -- objects and events: | |
| data Object | |
| data Event = Load | Etc | |
| -- We have an addEventListener. | |
| addEventListener | |
| :: Event -- ^ Being listened for | |
| -> Object -- ^ The "listener". Often a function. | |
| -> Object -- ^ Whom to register the event with. | |
| -> Fay () -- ^ No return value. | |
| addEventListener event l r = _addEventListener e l r | |
| where | |
| -- (Can we do better than this?) | |
| e = case event of | |
| Load -> "load" | |
| Etc -> "banana banana" | |
| _addEventListener :: String -> Object -> Object -> Fay () | |
| _addEventListener = ffi "%3.addEventListener(%1, %2)" | |
| -- Here's an alternate that relies on "features" of Javascript that I am | |
| -- not actually familiar with. I was just clicking around the Chrome Dev | |
| -- Toolbar. This gets rid of the Object-to-String conversion mucking up the | |
| -- previous implementation. | |
| -- | |
| -- addEventListener = ffi "%3.addEventListener(%1.constructor.name, %2)" | |
| -- Anyway. Now hows'about alert. My brief reading leads me to understand | |
| -- that one should qualify names when possible. | |
| alert :: String -> Fay Object | |
| alert = ffi "window.alert(%1)" | |
| -- Need to get the window. Don't try to use ffi functions as text | |
| -- templates; you must stick an object in where an object is required. One | |
| -- such place is '%3' in _addEventListener. It would not be sufficient to | |
| -- have the third argument to _addEventListener be a String. | |
| getWindow :: Fay Object | |
| getWindow = ffi "window" | |
| -- So! | |
| hw2 = do | |
| win <- getWindow | |
| fn <- alert "Hello world!" | |
| addEventListener Load fn win | |
| main = hw2 | |
| -- Compile this file with "fay --html-wrapper hello_fay.hs", then open | |
| -- hello_fay.html in a browser. |
Author
My fear of going down that path is I'd end up shoehorning JS' complete prototype heirarchy into Fay, which sounds like a bad idea. Is "alert(%1)" a Function, an Object, an EventListener, ...? Will I have to make a new instance declaration every time I need to use a new interface?
Not that I disagree, of course. There's no sense using Fay if we just retreat to the un(i)typed style. This seems like an area for thought and care. I merely punted on all that to finish the example. :)
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
I would restrict the types a bit, calling everything
Objectis not very descriptive, instead you could split addEventListener up into several functions, one that takes a Window, one for Element etc, or something like fay-jquery does forselect: