Tuesday, March 31, 2009

Location Stamper: Putting Moby Scheme To Work

I was so impressed with Moby Scheme I just had to give it a try. So, instead of going to bed on time last night, or working on billable work this morning I hacked some scheme.

I decided I'd write a trivial program: Location Stamper. The idea isn't particularly exotic - you have a small app running on your phone. Whenever you want, you click the screen and a message is logged to a twitter account with your current location. It might be useful, but probably isn't. As a side note, I chose to record the data in Twitter, because it's effectively an easy to integrate, always online, free for anyone to access database. How generous of them.

So far, I've taken the program from idea, to Moby Scheme, to running on the Android Emulator. I need to do a bit more homework before I can figure out how to run developed apps on my cell phone. I was hoping it was trivial to do, but alas, I couldn't find the quick and dirty instructions. But, this is hardly Moby Scheme's fault - I know I've got a Android application ready to go.

So, here's the code and some comments to explain what's going on:

;; The first three lines of this file were inserted by DrScheme. They record metadata
;; about the language level of this file in a form that our tools can easily process.
#reader(lib "htdp-beginner-reader.ss" "lang")((modname location-stamper) (read-case-sensitive #t) (teachpacks ()) (htdp-settings #(#t constructor repeating-decimal #f #t none #f ())))
;;
;;This is a basic Android APP that is used to record your current GPS coordinates
;; in a twitter feed at the click of a button. Useful? Not really. Intersting,
;; none the less
;;

;; Include our standard libraries
(require moby/stub/net)
(require moby/stub/world)
(require moby/stub/location)
(require moby/stub/parser)

;; Not sure if our URLs will grow too long for Twitter, but it's trivial to tinyurl
;; them.
(define (url->tinyurl u)
  (get-url (string-append "http://tinyurl.com/api-create.php?url=" u)))


;; Constants.
(define twitter-username "locationlog")
(define twitter-password "wouldn'tyouliketoknow")
(define WIDTH 320)
(define HEIGHT 480)

;; Our world. The current location and a comment about that location.
(define-struct loc (lat lng comment))


;; Various functions to convert stuff to strings. Our world to strings,
;; and just a lat and lng to string
(define (lat-lng->string lat lng)
  (string-append (number->string (exact->inexact lat)) ","
                 (number->string (exact->inexact lng))))
(define (loc->string w)
  (string-append (lat-lng->string (loc-lat w) (loc-lng w)) " "
                 (url->tinyurl (string-append "http://maps.google.com/maps?q=" (lat-lng->string (loc-lat w) (loc-lng w))
                                              "%26z=10"))))
                 
  
;; Like the name says, our initial world
(define initial-world (make-loc 0 0 "Initial location set to zero"))

;;
;; Our callback functions that make this all work. This is where Moby Scheme really shines.
;; Each function takes in our world an returns our world, and is indepdent and clean.
;;
(define (update-location w lat lng)
  (make-loc lat lng
            (string-append "Location updated: " (lat-lng->string lat lng))))
  
(define (log-location w b1 b2 type)
    (if (eq? type 'button-up)
        (make-loc (loc-lat w) (loc-lng w)
                  (string-append "Twitter status: " (twitter-update twitter-username twitter-password
                                                                    (string-append (loc->string w)))))
        w))

(define (render w)  
  (place-image
   (text (loc-comment w)  10 "black")
   20 20
   (empty-scene WIDTH HEIGHT)))

;;
;; Get this party started!
;;
(big-bang WIDTH HEIGHT 5 initial-world)
(on-redraw render)
(on-location-change update-location)
(on-mouse log-location)

I'd show a screenshot, but there's really not all that much to see.

Now for some feedback...

Gotchas

I ran into a handful of items that made development of this tiny program harder than I expected. One of the biggest issues I had was that running DrScheme in Beginning Student Mode is painfully slow (on Windows, Vista) for me. I use it for production code all the time, and the performance is just fine. If I had to guess, I'd say it was the code coverage tool that was chewing up CPU. Regardless, it's just no fun to develop in an environment that moves slowly.

As a side note - I found the develop and test in DrScheme, then use command line tools to generate and compile Java, worked quite well. Even when it came to modifying the generated Java code, I didn't have a problem. The development loop, I assume, could get smoother, but is quite usable now.

The other big gotcha I ran into was that lack of services offered by the API. For example, there's a very cool get-url that grabs the contents of a URL, but there was no way to set the HTTP headers on this request, or even an easy way of URL encoding parameters. The HTTP header issue meant that in order to implement twitter-update I had to write code at the Moby Framework level, rather than the application level. This included writing a Scheme stub of twitter-update as well as a Java specific twitterUpdate(...). While I was impressed with how easy it was to add this functionality in, it still slowed down development significantly. I assume this is a fairly temporary problem, and as time goes on, services will evolve and fill out completely.

Finally, having Moby Scheme depend on the Beginning Student Language is a double edged sword. It's excellent for those learning to program (which is Moby's target audience, and that's a good thing!), but it does make writing apps quickly and efficiently frustrating. It's actually amazing how complete a program you can write when a function can only have a single statement in it, and you can't use begin or let. I actually found programming Beginning Language mode kinda fun.

Final Thoughts

I think the bottom line is that Moby has plenty of growing to do, and even when it has a more complete library, it's probably not going to be the best option for production Android programming. But who cares! Heck, those aren't the goals of the project. If you're looking for a I'd like to teach my friend/kid/husband/wife how to program, this is an excellent place to start. And when the kinks are worked out of it, developing little apps should be a terrifically fun. I'm seeing visions of hand held web mashups in 25 lines of code or less...

Whether your a Scheme head or not (especially if you're not), this is a fun project to keep an eye on.

Update: I figured out how to install apps on my phone, it's not too painful at all. Now the real fun can begin!

9 comments:

  1. Congrats on your first application! Thanks for the very good critical feedback.

    Some of these issues will ease up with user contributions (and our own) of more API calls. The "getting it to run on the phone" problem will go away entirely with the Web interface: upload a file, get a link in the mail, click on it from your phone, and it installs. The service is essentially ready, we just need to test it a little more.

    ReplyDelete
  2. Antonio5:02 PM

    Have you tried out Kawa Scheme on the Android platform?

    http://per.bothner.com/blog/2008/AndroidHelloScheme/

    ReplyDelete
  3. Hey -- can you say more about the BSL slowdown? If you have debugging enabled (ie the defaults) in the module language, you shoud be seeing roughly comparable performance for comparable programs.

    ReplyDelete
  4. Ah, what I wrote before was just completely wrong. Indeed, it was a factor of 10 slower on a tight loop like this one:

    (define (f x) (if (zero? x) 1 (f (- x 1)))))
    (f 100000)

    (if you don't have a horribly slow laptop like mine, you'll probably want to add another zero in the second line to get something that takes some actual time)

    Anyways, you were right that the problem was in test coverage. The annotations that recoded what code had been run were particularly slow. I've improved that some and the teaching languages should only be 20% slower on tight loops like the ones below (now in SVN).

    ReplyDelete
  5. Shriram -

    I'm glad my feedback was useful. I'll keep an eye out for the web interface you guys are planning, it sounds really slick.

    Thanks again for helping to make this project happen, it's really wonderful.

    ReplyDelete
  6. Antonio -

    I haven't tried Kawa yet on Android, it's definitely on the list. And I thought I might give SISC a try too.

    Thanks for the recommendation.

    -Ben

    ReplyDelete
  7. Robby -

    Thanks for taking the time to do some debugging of the BSL slow down I mentioned.

    I guess the obvious question is, can I turn off code coverage some how?

    Is there some way I can manually import the procedures and syntax of BSL without actually having to go into that mode completely?

    Thanks,
    Ben

    ReplyDelete
  8. I think you'll find it isn't slow anymore, so no need to turn anything off in BSL.

    If you can't get ahold of the SVN version, then try starting you file with this first line:

    #lang s-exp lang/htdp-beginner

    and using the Module language.

    ReplyDelete
  9. Robby -

    Thanks for the tip and the fix - I'll see if I can grab it next time I work on Moby code.

    -Ben

    ReplyDelete