Hacking

Oct 19, 2006 18:52

I've decided that I should get to learn more about Haskell, because (from what totherme, michiexile and Duncan say) it sounds like it's got much cooler since I last touched it. So today I sat down to write a program to generate valid Siteswaps for juggling patterns. A siteswap is a list of throw heights: "5" means that you throw a ball sufficiently high that the ( Read more... )

computers, beware the geek, maths, haskell, juggling

Leave a comment

Comments 18

totherme October 19 2006, 18:50:57 UTC

-- newtype SiteSwap = SS [Int] deriving (Show, Read, Eq, Ord)
-- this just turned out to be a hassle

That's because, of the 3 ways in haskell to declare new data types, you've picked the wrong one :)

The three ways are: ["data", "type", "newtype"]

data actually creates a new data structure, using the sort of syntax you were aiming for there. Like "data Tree x = Leaf x | Branch (Tree x, Tree x)" etc...

This is great if you're doing something genuinely new, but there, you weren't. You actually just wanted a list of Ints, but you wanted to refer to them as something else. For that, we have type synonyms. To make your programme do what you want, add the line:

type SiteSwap = [Int]

And do a s/[Int]/SiteSwap/ over the rest of the code. I just tried it in my copy - it works. (there's no need for all the deriving stuff there - the new type has all the properties of the old one, including the ones you were trying to derive)

As for newtype - I believe it does something useful, but I've not yet sat down and read what ;)

Reply

totherme October 19 2006, 19:01:31 UTC
...and of course, I had to go look it up after writing that:

http://www.cs.auckland.ac.nz/references/haskell/haskell-intro-html/moretypes.html

All of this works using a data declaration instead of a newtype declaration. However, the data declaration incurs extra overhead...

So, I feel justified in not bothering about them for the most part ;)

Reply

totherme October 20 2006, 14:15:10 UTC
Ah, cool. Thanks!

To clarify, I'm not (yet) criticizing Haskell's type system, just my own understanding of it. Things are improving: I'm starting to remember some of the common pitfalls and avoiding them.

Reply

totherme October 20 2006, 15:22:31 UTC

To clarify, I'm not (yet) criticizing Haskell's type system

Good, good ;)

Just thinking about that though - it might be worth, when you get what appears to be a spurious type error, taking a copy of the code that produced the error, hiding it, and getting on with your debugging. Then, when you have a working programme, see if the code actually meant what you were thinking at the time - or if real runtime bugs were caught.

Of course, that would have been fairly pointless in this case, since a bug in constructing a type is genuinely one you can avoid by not having types ;)

Reply


totherme October 20 2006, 00:14:24 UTC
And after a few hours of playing, I think I now have some understanding of what a SiteSwap actually is :)

There's only one style point I think I noticed while I was playing, and that's the advance function. Do you really need it? It seems to me that all it does is aggregate one common argument of two distinct 2-arg functions. You could probably do:

where newfalling = advanceFalling s falling
newfallen = advanceFallen falling fallen

...instead. I dunno - doing without advance saves about 1 line in this particular file - if you were using it somewhere else too, the saving would go the other way. Meh :)

As for the rest, it's just knowing what libraries are out there :)

Take a look at Data.List - it contains the function inits, which allows you to refactor prefixes into prefixes = drop 1 . inits - which is pretty cool. It also contains findIndices, which allows us to render prefixes and isRepeated obsolete by redefining:

isRepetitive [] = False ( ... )

Reply

pozorvlak October 20 2006, 14:41:24 UTC
Aha, nifty. Another problem I came across was that of stripping out words that were cyclic permutations of words that had already occurred - 531 (which is really short for 531531531531531...) is counted as the same pattern as 315 and 153. I wonder if Data.List would help me there? I managed to get it down to four or five lines in the end, and I'm quite proud of the code I wrote to generate the cyclic permutations of a given word:

cyclicPerms xs = take n $ map (take n) $ iterate tail $ cycle xs
where n = length xs

(from memory)

Unfortunately, this wasn't as serious as the other bug I found - most of the patterns generated aren't actually juggleable! I think my test needs to be made stricter, but I'm not quite sure how :-(

Reply

totherme October 20 2006, 15:45:11 UTC
Can you give examples of patterns which aren't juggleable (but do pass isJuggleable) ?

Ideally, with an explaination as to why they're not juggleable ;)

Reply

totherme October 20 2006, 16:02:16 UTC
Ah! Resource allocation!

I'm guessing that the pattern 4100 isn't juggleable, since:

Since hands alternate, odd-numbered throws send the ball to the other hand, while even-numbered throws send the ball to the same hand.

So, in the pattern 4100, starting with the left, the left hand would always be throwing to itself, and the right hand would always be throwing to the left. So where do the balls come from? And since twice as many balls land in the left as are thrown by it, where do they go?

In my copy of the programme, 4100 passes the isJuggleable test - because it only checks for colisions, not resourcing.

I suppose that might be fixable by crossing your arms at appropriate points to even out the resourcing, but at that stage, my grip on the rules of our model get shakey ;)

Reply


totherme October 20 2006, 09:54:42 UTC
Oh - and if you want to be able to construct juggleablePatterns from numbers greater than 9, you might want to change concatMap show to map (unwords.show) :)

Reply

pozorvlak October 20 2006, 14:49:19 UTC
The usual approach is to use A for 10, B for 11, and so on. A throw with a weight of Z would have an airtime of 35 beats, and would thus have to be thrown about 1000 times as high as a throw from a three-ball cascade with the same rhythm, so I think we can ignore higher-weight throws for the purposes of discovering human-juggleable patterns :-)

Reply

totherme October 20 2006, 15:12:31 UTC
map (concat $ toBase ([0..9]++['a'..'z'])) ? :)

Reply


stronae October 22 2006, 17:16:03 UTC
I'm tickled that you're using Haskell for this, but I agree that getting used to the type system is a major pain.

Reply


Leave a comment

Up