1 What is Moby?
2 Quick Start
3 Running and packaging Android programs
run-in-browser
create-android-phone-package
4 Phone API
4.1 Location (GPS)
on-location-change
4.2 Motion sensors and tilt
on-acceleration
on-shake
on-tilt
4.3 Internet access
Version: 5.0.1

Moby: Racket for Mobile Phones

1 What is Moby?

Moby is a project from the PLT team. The Moby compiler consumes Advanced Student Language (ASL) programs that use World primitives, and produces applications for mobile platforms. The current prototype supports web browsers and smartphones. Our long-term goal is to make Racket 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.

Moby requires Racket 5.0.1.

2 Quick Start

Let’s see if Moby has been installed on your system. Run the following simple program.
  #lang planet dyoo/moby:3:5
  "hello world"
  true
  (define (f x) (* x x))
  
  (check-expect (f 42) 1764)
  
  (check-expect (map f '(1 2 3 4 5))
                (list 1 4 9 16 25))

On the very first run of this program, Racket may pause as it installs the Moby PLaneT package and generates its documentation. Expect to wait a few minutes for the installation to complete.

Moby programs can run in DrRacket as long as they don’t use any Javascript-specific functions. Let’s create a simple application that does use a Javascript context. The following example shows a rapidly incrementing counter. Create a file "counter.rkt" in the Module language with this content:

  #lang planet dyoo/moby:3:5
  (define initial-world 0)
  (big-bang initial-world (on-tick add1))

This program can be partially executed in Racket, but evaluation will halt on the big-bang because it’s a function that requires a Javascript context. The function run-in-browser can be used to provide a Javascript environment in your web browser:

  #lang racket
  (require (planet dyoo/moby:3:5))
  (run-in-browser "counter.rkt")
This will bring up a web server and a browser window with the running program. As a warning, package generation may take about 30 seconds to complete.

Moby programs can be be translated to Android phone packages. To create an Android apk package, you can use create-android-phone-package. Create a file called "build-counter.rkt" with the following content:

  #lang racket
  (require (planet dyoo/moby:3:5))
  (create-android-phone-package "counter.rkt" "counter.apk")
Running this will take "counter.rkt" and compile it to an Android package "counter.apk".

Because Moby programs use the web, they can dynamically generate DOM trees and style them with CSS, as in the examples below.

This example renders the world as a paragraph of text, styled with a font-size of 30. It uses draw-page and draw-css to draw the web page. The background color of the paragraph changes as the world reacts to the clock tick.

  #lang planet dyoo/moby:3:5
  
  ; The world is a number.
  (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")
                ("background-color"
                 ,(format "rgb(~a, ~a, ~a)"
                          (modulo w 255)
                          (modulo w 255)
                          (modulo w 255))))))
  
  (big-bang initial-world
            (to-draw-page draw-html draw-css)
            (on-tick add1))

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:3:5
  (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://racket-lang.org/logo.png"))
          (list elt)
          (list (js-p '(("id" "aPara")))
                (list (js-text (format "~a" w))))))
  
  (define (draw-css w)
    '(("aPara" ("font-size" "50px"))))
  
  (big-bang false
            (to-draw-page draw-html draw-css))

One subtle point about this program is that elt is constructed at the toplevel so that the element persists from one call of draw-html to the next. If elt were inlined into draw-html’s definition, then the text field would be cleared with every world update.

We can also use phone-specific features, such as geolocation. The following program shows the current location.
  #lang planet dyoo/moby:3:5
  (require (planet dyoo/moby:3:5/phone/location))
  
  (define (make-message w lat lng)
    (format "I think I am at: ~s ~s" lat lng))
  
  (big-bang "initial state"
            (on-location-change make-message))

Note that the program requires phone/location, one of the modules provided by this package. If this program is evaluated with run-in-browser, the browser environment will provide a control at the bottom of the page to allow the user to inject artificial GPS positions for testing.

The last example is a phone mood ring called "mood-ring.rkt": it shows a single DIV whose background color is controlled by the phone’s orientation; it uses phone/tilt to get at the orientation of the phone, and arbitrarily maps it to a color.

  #lang planet dyoo/moby:3:5
  (require (planet dyoo/moby:3:5/phone/tilt))
  
  ; The world is a color.
  (define initial-world (make-color 0 0 0))
  
  ; tilt: world number number number -> world
  ; Tilting the phone adjusts the color.
  (define (tilt w azimuth pitch roll)
    (make-color (scale azimuth 360)
                (scale (+ pitch 90) 180)
                (scale (+ roll 90) 180)))
  
  ; scale-azimuth: number -> number
  ; Take a number going from 0-360 and scale it to a number between 0-255
  (define (scale n domain-bound)
    (inexact->exact (floor (* (/ n domain-bound) 255))))
  
  ; User interface.
  (define view (list (js-div '((id "background")))))
  
  (define (draw-html w) view)
  
  (define (draw-css w)
    (list (list "background"
                (list "background-color"
                      (format "rgb(~a, ~a, ~a)"
                              (color-red w)
                              (color-green w)
                              (color-blue w)))
                (list "width" "300")
                (list "height" "300"))))
  
  
  
  (big-bang initial-world
            (on-tilt tilt)
            (to-draw-page draw-html draw-css))

Again, to package the program, we use create-android-phone-package.

  #lang racket
  (require (planet dyoo/moby:3:5))
  (create-android-phone-package "mood-ring.rkt" "mood.apk")

3 Running and packaging Android programs

 (require (planet dyoo/moby:3:5))

(run-in-browser input-file)  void
  input-file : path-string?
Runs the given input-file in a Javascript context.

(create-android-phone-package input-file    
  output-apk)  void
  input-file : path-string?
  output-apk : path-string?
Creates an Android phone package.

4 Phone API

The functions in this section provide access to features on a smartphone. In order to make testing easier, if these functions are used outside of a phone, Moby will inject mocks that allow the user to simulate phone events.

The other language bindings of Moby language are provided by the js-vm PLaneT package; please refer to the documentation of js-vm: (part ("(planet main.rkt (dyoo js-vm.plt 1 9))" "top"))

Here is an example that shows the status of all three sensors:

  #lang planet dyoo/moby:3:5
  (require (planet dyoo/moby:3:5/phone/tilt))
  (require (planet dyoo/moby:3:5/phone/location))
  
  (define-struct gps (lat lng))
  (define-struct tilt (a p r))
  (define-struct accel (x y z))
  
  (define-struct sensors (gps tilt accel))
  
  (define (update-gps w lat lng)
    (make-sensors (make-gps lat lng)
                  (sensors-tilt w)
                  (sensors-accel w)))
  
  (define (update-tilt w a p r)
    (make-sensors (sensors-gps w)
                  (make-tilt a p r)
                  (sensors-accel w)))
  
  (define (update-accel w x y z)
    (make-sensors (sensors-gps w)
                  (sensors-tilt w)
                  (make-accel x y z)))
  
  (big-bang (make-sensors (make-gps "loading" "loading")
                          (make-tilt "loading" "loading" "loading")
                          (make-accel "loading" "loading" "loading"))
            (on-location-change update-gps)
            (on-tilt update-tilt)
            (on-acceleration update-accel))

4.1 Location (GPS)

 (require (planet dyoo/moby:3:5/phone/location))

(on-location-change world-updater)  handler
  world-updater : (world [latitude number] [longitude number] -> world)
Constructs a world handler that watches for changes in the phone’s geographic location.

4.2 Motion sensors and tilt

 (require (planet dyoo/moby:3:5/phone/tilt))

(on-acceleration world-updater)  handler
  world-updater : (world [x number] [y number] [z number] -> world)
Constructs a world handler that watches acceleration updates.

(on-shake world-updater)  handler
  world-updater : (world -> world)
Constructs a world handler that watches the phone for shakes.

(on-tilt world-updater)  handler
  world-updater : (world [azimuth number] [pitch number] [roll number] -> world)
Constructs a world handler that watches changes in orientation.

4.3 Internet access

 (require (planet dyoo/moby:3:5/phone/internet))

This module does not provide any bindings, but is meant to notify create-android-phone-package if a program needs permission to access the internet. If your program is using image-url or js-img, add a require to this module.