Announcing Elm 0.3.5:
JavaScript Integration, Signal Filters, and more!

Before we start, here are some basic examples for those of you new to Elm. (Here are all the examples if you are looking for more.) OK!

Versions 0.3.x of the Elm compiler has two major goals:

  • Make Elm more practical.
  • Make it easy for anyone to help Elm grow.

The module system and JavaScript integration are important steps towards these goals, but I need your help to really accomplish the second goal. If you start an Elm project, write a useful module, or create a game, I encourage you to post it online for others to learn from and use! (And if you try one of these things and run into trouble, ask for help on the mailing list.)

Ok, now that I’ve pestered you about sharing your code and experiences with the internet (do it!), let’s get to the details of the release.

 

The JavaScript Event Interface

The JavaScript Event Interface (JSEI) makes it possible for an Elm program to communicate with JavaScript. More specifically, Elm can now send and receive JavaScript events.

Examples

I have created a couple example programs that use the JS Event Interface (JSEI) so you can see it in action (source). The three most exciting examples are probably:

  • FrameRate/ (source,result) which demonstrates a basic “game” that keeps a steady frame rate. If the users browser cannot handle the desired frame rate, the game will update as quickly as possible. For users that can handle the frame rate, it will update only as frequently as necessary to maintain the desired frame rate.
  • Maps/ (source,result) which demonstrates basic integration with OpenStreetMap.
  • Form/ (source,result) which is a simple form with client-side validation. This example needs the JSEI to redirect to a different page. I have gotten a couple questions about how to go about doing this, so now you know!

Now that you’ve seen the JSEI in action, lets talk about details.

Using the JavaScript Event Interface

The most important aspect of the JSEI is that it allows Elm to push imperative actions into JavaScript. This means Elm can gain fundamentally new features without having them explicitly added to the compiler. Here’s how you export events:

    foreign export jsevent "eventName"
        signal :: Signal JSString

This code snippet takes an Elm signal signal and broadcasts all of its values as an event named "eventName". Note that the type of the exported value must be a Signal of JavaScript values. Conversion from and to JavaScript values happens with functions from the Foreign.JavaScript module (docs and more docs). Importing values looks like this:

    foreign import jsevent "eventName"
        (castIntToJSNumber 0)
        signal :: Signal JSNumber

Notice that importing has one additional value: a default value. Elm was designed so that every signal is always defined. This default value will be the initial value of the imported signal. As soon as events come in, the signal will take their value. One thing to note is that — right now — these foreign definitions must come between any normal module imports and the beginning of your code.

The actual event protocol is fairly basic. An exported signals will produce some event outEvent. The exported value is accessible via outEvent.value. Similarly, when Elm receives an imported event inEvent, it will look for the imported value at inEvent.value. These points are probably better understood by looking through the examples linked above.

Built-in Event Listeners

As you may have seen in the examples, the amount of JavaScript code needed is actually pretty small if you just want to change the title, log messages, and redirect. To make these tasks even easier I have added three built-in event listeners: elm_title, elm_log, and elm_redirect. With these listeners, you can make some common imperative actions without having to worry about writing the JS yourself. For example:

    foreign export jsevent "elm_log"
        message :: Signal JSString

will log the current value of the message signal in the developer console of your browser. The user does not need to write any JS. elm_redirect and elm_titlework much the same way, except that they both ignore empty strings.

 

Filtering Signals

A signal always has a value, but the value changes discretely when events occur in the world. Elm’s new signal filtering functions allow you to block events, making the signal retain its previous value. This was not previously possible in Elm. The new filter functions are:

    keepIf      :: (a -> Bool) -> a -> Signal a -> Signal a
    dropIf      :: (a -> Bool) -> a -> Signal a -> Signal a
    keepWhen    :: Signal Bool -> a -> Signal a -> Signal a
    dropWhen    :: Signal Bool -> a -> Signal a -> Signal a
    dropRepeats :: Signal a -> Signal a
    sampleOn    :: Signal a -> Signal b -> Signal b

Notice that many of these functions require a default value. The danger of filtering is that no events ever make it through (keepIf (\_ -> False)). And as mentioned above, an undefined signal is a bad signal. For more detailed documentation see this. I have also created a couple examples of these functions in action: sampleOnkeepIf, and dropRepeats.

 

More!

Elm now uses a more compact format for strings. This should make strings 10-12 times more space efficient than in previous releases. Anecdotal evidence: Elm’s home page is now 70% of its previous size. Thank you to Conrad Parker for suggesting this simple and clever space saving technique! There are two more signal values as of this release (docs and docs). They don’t really fall into the category of filtering, but these dovetail with the filtering functions quite nicely.

    count  :: Signal a -> Signal Int
    clicks :: Signal ()

I also added one new function to Data.List (docs!):

    last :: [a] -> a

And of course, a couple of miscellaneous bugs have been fixed. I hope I found them before you did!

 

I hope you will give Elm a try! Follow these instructions to if you installing for the first time or upgrade with cabal update; cabal install elm.


Tags:

 
 
 

Comments are closed.