1 What is Moby?
2 Running Moby from Dr Scheme
3 The Moby World API
3.1 Types
3.2 dom-element constructors
3.3 Stimulus Handlers
3.4 Effects
make-effect: none
make-effect: beep
make-effect: play-sound
make-effect: stop-sound
make-effect: pause-sound
make-effect: set-sound-volume
make-effect: raise-sound-volume
make-effect: lower-sound-volume
make-effect: set-beep-volume
make-effect: play-dtmf-tone
make-effect: set-wake-lock
make-effect: release-wake-lock
make-effect: send-sms
make-effect: pick-playlist
3.5 API Extensions
4 Building Android packages
4.1 Android Dependencies for local compilation
5 Underlying developer details
5.1 Developer Dependencies
5.2 Setting up the Moby sources from github
5.3 Running the bootstrapper
5.4 Running Moby from the command line
5.5 Compiler
5.5.1 An example
5.6 Runtime
6 Appendix
6.1 Bindings from ASL
6.2 Unimplemented forms
Version: 5.0.1

Moby: the Moby Scheme Compiler

1 What is Moby?

Moby is a project from the PLT Scheme team. The Moby compiler consumes Advanced Student Language (ASL) programs that use World primitives, and produces applications for mobile platforms. The current prototype supports desktop browsers and smartphones. Our long-term goal is to make Scheme the premiere reactive scripting language for mobile phones.

Shriram Krishnamurthi presented the ideas behind Moby at ILC 2009 in his talk The Moby Scheme Compiler for Smartphones.

2 Running Moby from DrScheme

To use Moby from DrScheme, create a file in the Module language, and at the top of your program, include the following language line:

  #lang planet dyoo/moby:2:38

followed by the program. For example, running the program:

  #lang planet dyoo/moby:2:38
  (define initial-world 0)
  (js-big-bang initial-world (on-tick 1 add1))

will invoke a web browser, which should show the running program on a web page. Because on-tick is used, as every second passes, the runtime sends a tick stimulus to the program. The page should also provide links to download packages of the compiled program.

These programs run on the user’s web browser; they can also dynamically generate DOM trees and style them with CSS, as in the examples below.

The following example renders the world as a paragraph of text, styled with a font-size of 30. It uses draw-html and draw-css to draw the web page.

  #lang planet dyoo/moby:2:38
  (define initial-world 0)
  (define (draw-html w)
    (list (js-p '(("id" "myPara")))
          (list (js-text "hello world"))))
  (define (draw-css w)
    '(("myPara" ("font-size" "30"))))
  (js-big-bang initial-world
               (on-draw draw-html draw-css))

The next example shows an image and an input text field. As with the previous example, it uses draw-html and draw-css to construct the web page, and every time the world changes, the runtime environment reacts by re-drawing the web page.

  #lang planet dyoo/moby:2:38
  (define (form-value w)
    (format "~a" w))
  (define (update-form-value w v)
    (string->number v))
  (define elt
    (js-input "text" update-form-value))
  (define (draw-html w)
    (list (js-div)
          (list (js-img "http://plt-scheme.org/logo.png"))
          (list elt)
          (list (js-p '(("id" "aPara")))
                (list (js-text (format "~a" w))))))
  (define (draw-css w)
    '(("aPara" ("font-size" "50px"))))
  (js-big-bang 0
               (on-draw draw-html draw-css))

3 The Moby World API

(js-big-bang a-world handlers ...)  void
  a-world : world
  handlers : handler?
A Moby program starts a reactive computation with js-big-bang. The rest of the arguments hook into the reactive computation.

By default, the page that’s displayed contains a rendering of the world value. In the presence of an on-draw or on-redraw handler, js-big-bang will show a customized view.

The majority of the handlers register different stimuli that can trigger changes to the world. One instance is on-tick, which registers a function to update the world on a clock tick.

(on-draw to-dom to-css)  scene
  to-dom : (world -> (DOM-sexp))
  to-css : (world -> (CSS-sexp))
One of the main handlers to js-big-bang is on-draw, which controls how the world is rendered on screen. The first argument computes a rendering of the world as a DOM tree, and the second argument computes that tree’s styling.

(on-redraw hook)  handler?
  hook : (world -> scene)
For simple applications, on-redraw is sufficient to draw a scene onto the display. The following program shows a ball falling down a scene.

  #lang planet dyoo/moby:2:38
  (define WIDTH 320)
  (define HEIGHT 480)
  (define RADIUS 15)
  (define INITIAL-WORLD 0)
  (define (tick w)
    (+ w 5))
  (define (hits-floor? w)
    (>= w HEIGHT))
  (check-expect (hits-floor? 0) false)
  (check-expect (hits-floor? HEIGHT) true)
  (define (render w)
    (place-image (circle RADIUS "solid" "red") (/ WIDTH 2) w
                 (empty-scene WIDTH HEIGHT)))
  (js-big-bang INITIAL-WORLD
               (on-tick 1/15 tick)
               (on-redraw render)
               (stop-when hits-floor?))

(stop-when stop?)  handler?
  stop? : (world -> boolean)
When the world should be stopped – when stop? applied to the world produces true – then the js-big-bang terminates.

The program:
  #lang planet dyoo/moby:2:38
  (define (at-ten x)
    (>= x 10))
  (js-big-bang 0
               (on-tick 1 add1)
               (stop-when at-ten))
counts up to ten and then stops.

3.1 Types

A dom-sexp describes the structure of a web page:

  dom-sexp = (list dom-element dom-sexp ...)

a css-sexp describes the structure of a page’s styling:

  css-sexp = 
(listof (cons (or dom-element string)
              (listof attrib)))

An attrib is a:
  attrib = (list string string)

Each of the dom-elements can take in an optional attribute list to assign to the new dom element; the common useful attribute is a key-value binding for an "id", which can be used to identify an element in the css-drawing function.

Here are examples of a dom-expr and a css-sexp.
  (define a-dom-sexp (list (js-div '(("id" "main-div")))
                           (list (js-text "Hello world"))))
  (define a-css-sexp (list (list "main-div"
                                 (list "background" "white")
                                 (list "font-size" "40px"))))

3.2 dom-element constructors

Here are the dom-element constructors.

(js-div [attribs])  dom-element?
  attribs : (listof attrib?) = '()
Constructs a div element.

(js-p [attribs])  dom-element?
  attribs : (listof attrib?) = '()
Constructs a paragraph element.

(js-button world-update-f [attribs])  dom-element
  world-update-f : (world -> world)
  attribs : (listof attrib) = '()
Constructs a button. When the button is pressed, the world is updated through world-update-f.

The following example counts how many times a button has been clicked.
  #lang planet dyoo/moby:2:38
  (define (press w)
    (add1 w))
  (define (draw w)
    (list (js-div)
          (list (js-button press) (list (js-text "Press me")))
          (list (js-text (format "Button presses: ~a" w)))))
  (define (draw-css w)
  (js-big-bang 0
               (on-draw draw draw-css))

(js-button! world-update-f effect-f [attribs])  dom-element
  world-update-f : (world -> world)
  effect-f : (world -> effect)
  attribs : (listof attrib) = '()
Constructs a button. When the button is pressed, the original world is updated, and the original world is used to construct an effect.

(js-text text)  dom-element
  text : string?
Constructs regular text.

(js-input type world-update-f [attribs])  dom-element
  type : string
  world-update-f : 
(or/c (world string -> world)
      (world boolean -> world))
  attribs : (listof attrib) = '()
Creates an input form element. The types that are currently supported are:
  • "text"

  • "password"

  • "checkbox"

When the user changes the content of the form element, the runtime uses world-update-f to update the world. If the type is either "text" or "password", then the string value of the element will be passed as the second argument to it. If type is "checkbox", a boolean representing the checked status of the element will be passed to it.

The example below has a single text input form element, which allows the user to enter some value.
  #lang planet dyoo/moby:2:38
  (define (refresh w form-val)
  (define input-node
    (js-input "text" refresh '(("id" "myname"))))
  (define (draw w)
    (list (js-div)
          (list (js-div) (list (js-text (format "I see: ~s~n" w))))
          (list (js-div) (list input-node))))
  (define (draw-css w)
  (js-big-bang ""
               (on-draw draw draw-css))

The example below uses a checkbox to select among three elements:
  #lang planet dyoo/moby:2:38
  (define (make-ingredient-checkbox-sexp ingredient)
    (local [(define (on-check w v)
                 (cons ingredient w)]
                 (remove ingredient w)]))]
      (list (js-div)
            (list (js-text ingredient))
            (list (js-input "checkbox"
                            `(("value" ,ingredient)))))))
  (define c1 (make-ingredient-checkbox-sexp "mushrooms"))
  (define c2 (make-ingredient-checkbox-sexp "green peppers"))
  (define c3 (make-ingredient-checkbox-sexp "olives"))
  (define (draw w)
    (list (js-div)
          (list (js-text (format "The world is: ~s" w)))))
  (define (draw-css w)
  (js-big-bang '()
               (on-draw draw draw-css))

(js-img url [attribs])  dom-element
  url : string
  attribs : (listof attrib) = '()
Creates an image element.

(js-select options world-update-f [attribs])  dom-element
  options : (listof string?)
  world-update-f : (world string -> world)
  attribs : (listof attrib) = '()
Constructs a select element with the given options. Whenever a new option is selected, the world-update-f function is called to get the new world.

The example below has a select with five elements.
  #lang planet dyoo/moby:2:38
  (define (select-house w an-option)
  (define a-select-element
    (js-select (list ""
  (define (draw w)
    (list (js-div)
          (list a-select-element)
          (list (js-text (format "House: ~a" w)))))
  (define (draw-css w)
  (js-big-bang ""
               (on-draw draw draw-css))

3.3 Stimulus Handlers

Stimulus handlers are provided as additional arguments to a js-big-bang.

Each stimulus has an effect-less and an effect-full version; the effect-full version allows you to provide an effect-generating function as well as a world-updater. When the given stimulus emits, the old world is used to compute both the new world and the optional effect. Afterwards, each effect in the effect group is applied.

  effect = atomic-effect
  | (listof effect)

(on-tick delay world-update-f)  handler
  delay : number
  world-update-f : (world -> world)
(on-tick! delay world-update-f effect-f)  handler
  delay : number
  world-update-f : (world -> world)
  effect-f : (world -> effect)
Delays by n seconds, and then calls the handlers.

(on-shake world-update-f)  handler
  world-update-f : (world -> world)
(on-shake! world-update-f effect-f)  handler
  world-update-f : (world -> world)
  effect-f : (world -> effect)
Calls the shake handlers when the phone is physically jerked.

(on-location-change world-update-f)  handler
  world-update-f : (world (lat number) (long number) -> world)
(on-location-change! world-update-f    
  effect-f)  handler
  world-update-f : (world (lat number) (long number) -> world)
  effect-f : (world number number -> effect)
Calls the location handlers when the latitude or longitude of the device has changed.

(on-tilt! world-update-f effect-f)  handler
  world-update-f : (world number number number -> world)
  effect-f : (world number number number -> effect)
Calls the tile handlers when the phone has been tilted.

(on-acceleration world-update-f)  handler
  world-update-f : (world number number number -> world)
(on-acceleration! world-update-f effect-f)  handler
  world-update-f : (world number number number -> world)
  effect-f : (world number number number -> effect)
Calls the acceleration handlers when the device feels change in acceleration.

(on-sms-receive world-update-f)  handler
  world-update-f : (world (sender string) (message string) -> world)
(on-sms-receive! world-update-f effect-f)  handler
  world-update-f : (world (sender string) (message string) -> world)
  effect-f : (world (sender string) (message string) -> effect)
Calls the sms-receiving handlers when the phone is physically jerked. The first string is the sender’s address, and the second string is the message payload.

3.4 Effects

Effects allow world programs to apply side effects to the outside world. These are used in conjunction with the effect (!) version of the stimulus handlers described above.

(make-effect:none)  effect
No result when interpreted.
(make-effect:beep)  effect
Audible beep when interpreted. On an Android smartphone, uses the notification ringtone.

(make-effect:play-sound a-sound)  effect
  a-sound : sound
Plays a sound from the given sound. If the sound is already playing, then the sound continues to play.
(make-effect:stop-sound a-sound)  effect
  a-sound : sound
Stops playing a sound from the given url.
(make-effect:pause-sound a-sound)  effect
  a-sound : sound
Pauses a sound; if make-effect:play-sound for the same sound is given later, play restarts from the point where it was paused.

A sound is a:
  sound = string
  | playlist

(make-effect:set-sound-volume volume)  effect
  volume : number
Sets the sound volume; the number should be between 0 and 100.
Raises the sound volume. If the volume’s already at 100, has no effect.
Lowers the sound volume. If the volume’s set to 0, has no effect.

(make-effect:set-beep-volume volume)  effect
  volume : number
Sets the sound volume of the beep; the number should be between 0 and 100. On an Android smartphone, uses the notification sound.

(make-effect:play-dtmf-tone tone)  effect
  tone : number
On a smartphone, plays a DTMF tone, where tone is between 0 and 15 inclusive.

(make-effect:set-wake-lock flag)  effect
  flag : number
On a smartphone, sets the wake-lock flag to prevent the phone from sleeping. Low-level call.
On a smartphone, releases a wake-lock to allow the phone to go to sleep again.

(make-effect:send-sms phone-number message)  effect
  phone-number : string
  message : string
Sends an SMS message.

(make-effect:pick-playlist world-update-f)  effect
  world-update-f : (world playlist -> world)
Brings up a playlist picker; when a playlist is selected, the world is updated using world-update-f with the selected playlist sound.

3.5 API Extensions

The following helper functions and forms are provided by Moby.

(get-url url)  string?
  url : string?
Does an HTTP GET to download the string content from a URL.

As an example, if get-url is called on the URL to the PLT Scheme homepage,
  (get-url "http://plt-scheme.org/")
it produces the textual content of the "index.html" on the homepage.

(location-distance lat-1 long-1 lat-2 long-2)  number?
  lat-1 : number?
  long-1 : number?
  lat-2 : number?
  long-2 : number?
Given latitude-1, longitude-1, latitude-2, longitude-2, produces the distance between the locations in terms of meters.

(xml->s-exp xml-string)  s-expression?
  xml-string : string?
Parses a string containing XML to s-expressions.

(define-struct name (id ...))
define-struct will define structure constructors, selectors, mutators, and a predicate. e.g.

  (define-struct foo (a b))
defines the following forms:
  • make-foo: X Y -> foo

  • foo-a: foo -> X

  • foo-b: foo -> Y

  • foo?: any -> boolean

  • set-foo-a!: foo X -> void

  • set-foo-b!: foo Y -> void

(procedure-arity p)  (or/c number? (list/c 'at-least number?))
  p : procedure?
Returns the number of arguments a procedure accepts. If the procedure takes a minimum number of arguments, returns the list containing 'at-least and the minimum arity.

Creates a mutable hashtable whose keys are compared by eq?.

Creates a mutable hashtable whose keys are compared by equal?.

(hash? x)  boolean?
  x : any/c
Returns true if x is a hash, and false otherwise.

(hash-set! a-hash key value)  void
  a-hash : hash?
  key : any/c
  value : any/c
Mutates a-hash.

(hash-ref a-hash key value default-val)  any/c
  a-hash : hash?
  key : any/c
  value : any/c
  default-val : any/c
Looks up key in a-hash; if a value can’t be found,
  • If default-val is a thunk, calls it and returns its value.

  • Otherwise, returns default-val.

(hash-remove! a-hash key)  (void)
  a-hash : hash?
  key : any/c
Removes a key and its associated value from a-hash.

(hash-map a-hash f)  (listof any/c)
  a-hash : hash?
  f : (any/c any/c -> any/c)
Maps a function f across all the key/value pairs in a-hash, collecting results into a list. The order of the traversal is not defined.

(hash-for-each a-hash f)  (void)
  a-hash : hash?
  f : (any/c any/c -> any/c)
Applies a function f across all the key/value pairs in a-hash. The order of the traversal is not defined.

4 Building Android packages

Moby supports the building of Android ".apk" packages; programs built as Android packages can take advantage of native features of the device.

In order to generate Android applications, the only thing you’ll need is a connection to the Internet. When a Moby program is executed, the third link on the web browser’s page is a link to a Android .APK package. Clicking on the link triggers compilation on a web service, removing the need to install any of the Android SDK tools locally.

4.1 Android Dependencies for local compilation

If you still wish to generate programs for the Android+Phonegap backend using local tools, you’ll need the following:

Moby finds these by using find-executable-path; make sure that ant and the android binary are in your path; Moby will use your PATH variable to find Apache Ant and the Android SDK.

Note that if you’re using a version of the Android SDK greater than 1.5, you must still currently include support for the 1.5 API.

You can verify that android and ant can be found with the following at the interactions window:

  (find-executable-path "android")
  (find-executable-path "ant")

Both of these expressions must return non-false values for Moby to be able to build packages.

Running a Moby program generates a web page with links to run the program; once the Android SDK has been successfully installed, the link that’s named "Generate Android APK" will generate an Android package.

5 Underlying developer details

The compiler takes a ASL program and translates it to Javascript code. Moby reimplements the ASL primitives in a Javascript runtime library that’s included with the compiled application. (See doc/moby-developer-api.txt for more details.)

To support smartphones, Moby uses a bridge library called Phonegap, which provides access to the native facilities of several cell phones. In this way, Moby should be able to support multiple platforms with a lot of code reuse. Moby handles the other libraries (tilt, location, sms, music), though with support only for the Android platforms for now.

5.1 Developer Dependencies

Moby is mostly written in PLT Scheme, and the project sources are hosted by github.com. To develop with Moby, you will need the following:

5.2 Setting up the Moby sources from github

Moby is used as a PLaneT package; to install Moby from the development sources and set up a PLaneT local link.

Download the Moby source, currently hosted on github and place them somewhere convenient.

For example,

$ cd ~/work

$ git clone git://github.com/dyoo/moby-scheme.git moby

downloads the developer sources.

Next, add a PLaneT local link to the moby directory:

$ planet link dyoo moby.plt 2 <<some-high-number>> moby

with <<some-high-number>> replaced with a number greater than the latest released version of Moby.

Once this is done, the development link should be established, and you should be able to use Moby as before.

5.3 Running the bootstrapper

Whenever you first check out moby ,and whenever you make changes to the underlying kernel libraries (in "moby/support/js/runtime"), you will need to run the bootstrapper program "moby/src/bootstrap-js-compiler.ss". This generates a set of translated libraries and dependencies for the Moby runtime.

5.4 Running Moby from the command line

You can run the Moby command line utility ("moby/src/moby.ss") on a Moby program to produce a compiled version of your application. Moby supports two output backends, both which rely on Javascript:
  • js: compiles to a web page application, which can be deployed on any web server.

  • js+android-phonegap: compiles to an Android .apk application package; can also use features of the mobile platform.

By default, the command line utility will use the js backend.

Let’s run moby on the falling-ball.ss example in "moby/examples/falling-ball.ss". We can first generate a web program.

$ cd moby/examples

$ mred ../src/moby.ss falling-ball.ss

$ cd FallingBall/

$ ls

index.html  main.js  runtime  test

If you open up index.html from your web browser, you should see a red ball falling down the screen.

Furthermore, we may want to generate an Android application.

$ cd moby/examples

$ mred ../src/moby.ss -t js+android-phonegap falling-ball.ss

$ cd FallingBall

$ ls

AndroidManifest.xml  build.properties    gen               res

assets               build.xml           libs              src

bin                  default.properties  local.properties  tests


$ ls bin

classes  classes.dex  DroidGap.ap_  DroidGap-debug.apk

"DroidGap-debug.apk" is the compiled Android binary. The Ant "build.xml" build-script in the "FallingBall" directory can install, uninstall, and reinstall the application if the Android emulator is online.

    $ ant install

Buildfile: build.xml


[some output cut]



     [echo] Installing bin/DroidGap-debug.apk onto default emulator...

     [exec] 1594 KB/s (120997 bytes in 0.074s)

03:38 I/ddms: Created: [Debugger 8610-->1641 inactive]

03:38 I/ddms: Good handshake from client, sending HELO to 1641

     [exec]     pkg: /data/local/tmp/DroidGap-debug.apk

     [exec] Success

03:39 I/ddms: Closing [Client pid: 1641]



Total time: 6 seconds

After this, you can look at the Android emulator, which should now have the "FallingBall" application installed.

5.5 Compiler

Moby consists of the following core files for the compiler:
  • "src/compiler/beginner-to-javascript.ss": translates Scheme programs to javascript programs.

  • "src/compiler/env.ss": maintains the environment structures that map identifiers to bindings.

  • "src/compiler/permission.ss": defines a list of capabilities that a function can be tagged with.

  • "src/compiler/toplevel.ss": maps the primitive toplevel names available in the base language.

  • "src/compiler/modules.ss": adds a few extensions to the toplevel language, including the reactive world primitives.

  • "src/compiler/pinfo.ss": maintains program information used to analyze a program and figure out what functions are used and what capabilities are needed.

  • "src/compiler/desugar.ss": applies syntactic transformations on programs to a core form.

  • "src/compiler/helpers.ss": auxillary helper functions.

The compiler is intentionally written in a small superset of the language ("src/compiler/lang.ss"). As a consequence, it is self hosting, and we take advantage of this to produce a running compiler on the browser. ("support/js/test/test-repl.html")

5.5.1 An example

Let’s see what beginner-to-javascript.ss gives us:

> (define p '((define (f x)

                (* x x))


              (f 3)))


> (define cp (program->compiled-program p))

program->compiled-program consumes a program – a list of s-expressions – and produces a compiled-program structure.

> cp


The compiled program consists of a list of toplevel definitions and expressions.

> (compiled-program-defns cp)

"\nfunction f(x) { return plt.Kernel._star_([x,x]); }"


> (compiled-program-toplevel-exprs cp)

> cp


The compiled program consists of a list of toplevel definitions and expressions.

> (compiled-program-defns cp)

"\nfunction f(x) { return plt.Kernel._star_([x,x]); }"


> (compiled-program-toplevel-exprs cp)

"(function (toplevel_dash_expression_dash_show0) { \n\ntoplevel_dash_expression_dash_show0((f((plt.types.Rational.makeInstance(3, 1))))); })"

If we want to embed the evaluation of this program in a web page, we can use the two strings above to do so. For convenience, we provide a helper function compiled-program-main that ties both the definitions and expression evaluation together.

5.6 Runtime

The Javascript program that’s emitted depends on a runtime kernel that’s currently implemented in Javascript. See the files in "support/js/runtime".

6 Appendix

6.1 Bindings from ASL

The following toplevel bindings are available from Moby, and have the same meaning as in Advanced Student Language.

6.2 Unimplemented forms

The following ASL forms are currently unimplemented:
  • begin0

  • delay

  • shared

  • recur