Turtle Graphics :: Changing Interface

Recalling, my first idea of the Turtle Graphics posts was to see if it was likely that a beginner in functional programming would have invented monads by himself/herself.

Let’s change the interface a bit, such that a command is a function from log to log.

(I will reuse definitions from the original post, i.e. turtle definition and step)

> type Command = [Turtle] -> [Turtle]

> start = Turtle { x=0, y=0, alpha=0 }

> go, left, right :: Command
> go [] = []
> go (t:ts) = t {x = x t + step * cos (alpha t),
>   y = y t + step * sin (alpha t),

>   alpha = alpha t} : t : ts

> rotate :: Double -> Command
> rotate v [] = []

> rotate v (t:ts) = t {alpha = alpha t + v} : t : ts

> left = rotate (pi/2)
> right = rotate (-pi/2)

> execute :: [Command] -> Turtle -> [Turtle]
> execute cs l = (foldr (.) id cs) [l]

Basically, the primitive commands have to work on the whole list and consider the case of an empty list, whereas commands defined in terms of other commands don’t have that restriction. It’s also easy to define new commands:

> go3 = go . go . go

But the primitive commands don’t look good at all! But, it’s an easy fix..

The problem is of course with the type of Command. A primitive command only cares about the first turtle in the list (the newest one), so why should a command take a whole list as parameter?

> type Command = Turtle -> [Turtle]

> go, left, right :: Command
> go t = return $ t {x = x t + step * cos (alpha t),

  y = y t + step * sin (alpha t),
>   alpha = alpha t}

> rotate :: Double -> Command

> rotate v t = return $ t {alpha = alpha t + v}

> left = rotate (pi/2)
> right = rotate (-pi/2)

> — [Turtle] -> (Turtle -> [Turtle]) -> [Turtle]

> |>| :: [Turtle] -> Command -> [Turtle]
> [] |>| f = []

> (l:ls) |>| f = (f l) ++ (l:ls)

So, for go and rotate, we use a little trick, using return instead of putting the result in a list. What is much more interesting is that we now have a little asymmetry in the type of a command. It is not possible anylonger to use (.) for combining commands, so we define |>| to do that for us.

We must use a little lambda to define new commands..

> go3 = \t -> t |>| go |>| go |>| go

..but that shouldn’t be too much of a problem.

We’re not done yet, but at least we took care about our little logging problem we had the previous post.


About gustafnk

Developer at Jayway, REST/Hypermedia, AWD, Software apprentice, Dvorak user, Christian atheist, Zizek fan. I'm on twitter: @gustaf_nk
This entry was posted in haskell, turtle. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s