Skip to content
February 14, 2012 / cdsmith

Juggling in Haskell and Gloss

Just sharing what we’ve been talking about in my classes at LSV (Little School on Vermijo) the past few days.  It all started when a math teacher I follow on Google+ posted a link to this video on the mathematics of juggling, by Cornell professor Allen Knutson.

So we all watched the video, and talked about it… and then about midnight last night, I realized this would make a perfect introduction to Gloss simulations, which we’re learning about in our Haskell programming class!  Fast forward about 20 minutes of hacking, and we have this short program:

import Graphics.Gloss
thePattern = [5,2,5,1,2]
initial g = (-1, 0.0, [], cycle thePattern)
step dt (hand, time, balls, pattern) = (newhand, newtime, newballs, newpattern)
    where (throw, newtime) = properFraction (time + dt)
          newhand    = if throw == 1 then -hand else hand
          thrown     = if throw == 1 then [ (hand, newtime, head pattern) ]
                                     else []
          newpattern = if throw == 1 then tail pattern else pattern
          newballs   = [ (bhand, btime + dt, height)
                       | (bhand, btime, height) <- balls,
                         btime + dt < fromIntegral height ]
                       ++ thrown
draw (hand, time, balls, pattern) = pictures [
    juggler,
    pictures [ ball b | b <- balls ]
    ]
ball (bhand, btime, height) = translate (50*x) (50*y) (circleSolid 10)
    where t = 1 - 2 * (btime / fromIntegral height)
          x = if even height then bhand else bhand * t
          y = if height < 3 then 0 else fromIntegral (height - 1) * (1 - t^2)
juggler = pictures [
    line [(-50, 0), (0, 25), (50, 0)],
    line [(-30, -100), (0, -50), (30, -100)],
    line [( 0, 25), (0, -50)],
    translate 0 50 (circle 25)
    ]

Feel free to check it out.

This isn’t the best code in the world, because I deliberately write it to avoid as many ideas as I can that we haven’t talked about in my Haskell class.  Among those, for example, are any kind of user-defined data types, or any structured data other than tuples and lists!  I’ve also used list comprehensions when maps and filters might be clearer, for the same reason: we’ve done list comprehensions in class!  Those are coming soon, but for the time being, it’s not too hard to see what’s going on here.  A couple notes about the world type:

  • The state of world comprises four pieces of information: which hand will throw next, how much time has passed since the last throw, what balls are in the air, and what pattern is coming up next.  Since we don’t have user-defined types and it makes the math easy, I’ve described hands as -1 for left, and +1 for right.
  • The balls in the air form a list, but each element of that list is another tuple, containing the hand the ball was thrown from, how long it has been in the air, and its height.

So like all Gloss simulations, we need to specify three things:

  1. The initial state.  This is the left hand, no time since the last throw, no balls in the air, and the pattern sitting ahead of us.  The cycle function turns a finite list into an infinite repeating one.
  2. The step function.  This is where most of the logic sits… there are a lot of bits, but it does what you’d expect!  Every second, a ball is thrown, and the hand switches sides.  We update the balls to add to their time in the air, and keep only the ones that haven’t landed.  When a ball is thrown, we add it.  And each time we drop a number from the pattern.
  3. The draw function.  This draws the juggler and all of the balls.  The balls are drawn with some faux-physicsy thing that, frankly, is just the result of fiddling and isn’t an accurate physics simulation.  I can get away with that when teaching middle schoolers!  Hey, at least they follow parabolas; just not all with the same acceleration.  In class I just skimmed over the math for where the ball appears, since the class right now is about the state type, and drawing is something they’ve been doing all year anyway.

Definitely a lot of fun.  I encourage you to copy and paste the code above into http://dac4.designacourse.com:8000/sim and fiddle with the patterns and see what they look like!

4 Comments

Leave a Comment
  1. Matthias Felleisen / Feb 15 2012 4:48 pm

    Do you explain to your kids that the Gloss simulation integrates for them? Your use of ‘dt’ suggests you do. If you don’t, don’t be surprised if your middle school kids can understand the idea of integration from your simulation framework. It’s the same for our big-bang/world library. — Matthias

    • cdsmith / Feb 15 2012 7:13 pm

      Yes, we’ve talked a little about how what’s going on here is the same as what is happening in calculus… this is less impressive to kids who don’t yet know the pop culture stereotype that “calculus” is supposed to be hard. We have spent time talking about how it’s often easier to describe motion in terms of change than as a single closed expression based on time. Definitely the choice of dt was deliberate, and will hopefully be remembered when calculus class comes around. And yes, the students certainly understand the operational picture of what’s going on in terms of iterating the step function to update the state of the world.

  2. Scott Tucker / Feb 15 2013 5:45 pm

    Thanks for finally writing about >Juggling in Haskell and Gloss «
    Sententia cdsmithus <Loved it!

  3. hayd / Nov 6 2013 11:39 pm

    This was a really interesting video, thanks for sharing it. Unfortunately the links to designacourse no longer work. :(

    I also have a stupid question: I can’t get this code to compile (it complains about a lack of `main` function)…

Leave a comment