Friday, January 29, 2010

Deriving the Y Combinator in Erlang - Part 2: Abstraction

This is the second post in a series on the Y combinator. Part 1


In the last post on the Y combinator, we established that some functional languages (such as Erlang) make it hard to have recursive, anonymous functions. Namely, there is no name that is bound to the "current" anonymous function. Furthermore, we established that we could work around this problem by passing the anonymous function to itself. When we concluded, we had derived this much:

Foo = fun(AlsoFoo, N) ->
    case N of
        1 -> 1;
        _ -> N * AlsoFoo(AlsoFoo, N - 1)
    end
end,

Fact = fun(X) -> Foo(Foo, X) end

This post will focus on extracting the Y combinator from the above code. We will follow a sequence of transformations, each with a specific intent. In the end, we will hopefully have some beautiful code.

Reducing the Number of Arguments

This factorial algorithm started with a function that took a single parameter. This function called itself with successively smaller values, until it reached a base case. However, we muddied the waters by passing the function around as well. We would like to return to having a one-parameter function. We can accomplish this by creating another level of closure:

Foo = fun(AlsoFoo) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * (AlsoFoo(AlsoFoo))(N - 1)
        end
    end
end,

Fact = fun(X) -> (Foo(Foo))(X) end
Now it is clear that our recursive function is really only calling itself with one parameter.

Simplifying the Recursive Function Call

The place where we make the recursive call is rather ugly. We have to build the function upon which we will recurse before we can actually call it. It would be better if the recursive function was explicitly named. We can do that, too:

Foo = fun(AlsoFoo) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> 
                AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
                N * AlsoFooAlsoFoo(N - 1)
        end
    end
end,

Fact = fun(X) -> (Foo(Foo))(X) end

We can simplify the body further by moving AlsoFooAlsoFoo to a higher scope.

Foo = fun(AlsoFoo) ->
    AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * AlsoFooAlsoFoo(N - 1)
        end
    end
end,

Fact = fun(X) -> (Foo(Foo))(X) end

As an aside, you might find this step overly complicated. You may ask, why did we not simply define AlsoFooAlsoFoo = AlsoFoo(AlsoFoo). I hope to get into the details in a later post, but for now, just realize that would change the evaluation order in a bad way. Or, try it yourself and find out why it doesn't work.

Extracting the Anonymous Function

Right now, the body of our algorithm is embedded deeply within some necessary plumbing. We would like to extract our algorithm from the center of this. This is quite easy:

Foo = fun(AlsoFoo) ->
    AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
    FactRec = fun(Self) ->
        fun(N) ->
            case N of
                1 -> 1;
                _ -> N * Self(N - 1)
            end
        end
    end,
    FactRec(AlsoFooAlsoFoo)
end,

Fact = fun(X) -> (Foo(Foo))(X) end

Now we can pull it outside the body of Foo.

FactRec = fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end,

Foo = fun(AlsoFoo) ->
    AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
    FactRec(AlsoFooAlsoFoo)
end,

Fact = fun(X) -> (Foo(Foo))(X) end

Simplifying Fact

We're getting close, but the definition of Fact still leaves something to be desired. However, in order to make it simpler, we have to first make it messier. Start by moving Foo inside the definition for Fact:

FactRec = fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end,

Fact = fun(X) ->
    Foo = fun(AlsoFoo) ->
        AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
        FactRec(AlsoFooAlsoFoo)
    end,
    
    (Foo(Foo))(X)
end

Our goal is to build a general-purpose function Y that takes a function F and produces a self-recursive version of that function. Right now, the innermost part of Foo makes an explicit reference to FactRec. We want to eliminate that explicit reference:

FactRec = fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end,

Fact = fun(X) ->
    Y = fun(Proc) ->
        Foo = fun(AlsoFoo) ->
            AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
            Proc(AlsoFooAlsoFoo)
        end,
        Foo(Foo)
    end,
    (Y(FactRec))(X)
end

Now that we've done this, Y no longer has any bound variables, so we can pull it out of Fact completely:

FactRec = fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end,

Y = fun(Proc) ->
    Foo = fun(AlsoFoo) ->
        AlsoFooAlsoFoo = fun(Z) -> (AlsoFoo(AlsoFoo))(Z) end,
        Proc(AlsoFooAlsoFoo)
    end,
    Foo(Foo)
end,

Fact = fun(X) ->
    (Y(FactRec))(X)
end

Of course, if we want, we can simplify some of these definitions. Y can become a normal Erlang module function (rather than a function value). Fact itself can be curried - we can eliminate the noise of the explicit parameter. Also, FactRec doesn't need to be named anymore - it can become the anonymous function that we originally intended:

y(F) ->
    G = fun(AlsoG) ->
        F(fun(Z) -> (AlsoG(AlsoG))(Z) end)
    end,
    G(G).


Fact = y(fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end)

Unfortunately, the y function only supports functions that take a single parameter. Some languages have a "splat" operator that can be used to represent "all the parameters;" unfortunately, Erlang does not. Instead, it can be useful to define a family of y functions that deal with functions taking more than one parameter:

y2(F) ->
    G = fun(AlsoG) ->
        F(fun(Y, Z) -> (AlsoG(AlsoG))(Y, Z) end)
    end,
    G(G).

Conclusion

We have shown the difficulty in defining recursive, anonymous functions in Erlang. We showed a simple solution to this problem, and then generalized the plumbing to make it easier to use. While this is not necessary in all functional languages, I hope that this is useful to anybody working in a strict language, such as Erlang.

I am planning more posts on this topic. One post will explain the strange step I took in Simplifying the Recursive Function Call. Others will explain just what a fixed point is, what the fixed point combinators are, and how the Y combinator satisfies the definition of a fixed point combinator.

Monday, January 18, 2010

Deriving the Y Combinator in Erlang - Part 1: Intuition

This is the first of a series on the Y combinator. Part 2


When I heard about the fixed point combinators before, I didn't know what to make of them, so I filed the topic away in my brain. However, when I was working on implementing continuations in Erlang, I ended up building a small structure that reminded me of the Y combinator. With a little massaging, I extracted the actual Y combinator, and proceeded with what I was working on.

The actual definition of the Y combinator is insanely dense:

Y = λf·(λx·f (x x)) (λx·f (x x))
This is precisely why I didn't understand it at first - that definition means nothing to me. We need a more intuitive way to think about it.

Suppose you decide to write the factorial function in Erlang. A simple (by which I mean unoptimized) implementation might look like this:

fact(N) -> 
    case N of
        1 -> 1;
        _ -> N * fact(N - 1)
    end.
There's nothing particularly complicated here - we're just calling fact recursively. But what happens if you try to make fact into a fun (an anonymous function in Erlang). Watch:
Fact = fun(N) -> 
    case N of
        1 -> 1;
        _ -> N * ??? (N - 1) %%How do we call ourselves? Fact isn't yet bound!
    end
end.
In some languages, we could replace the ??? with Fact. Unfortunately, Erlang doesn't let you do this. If you tried, Erlang would say that Fact is unbound. This is true - until we've finished defining the fun, we can't assign it to Fact. Other languages provide you with a magic variable that represents the current function (Javascript has arguments.callee). Again, as far as I know, Erlang doesn't provide such a variable. Does that mean that we have no hope?

Let's look at this problem one step at a time. We need something to stand in for the ???. We need a name that represents the current, anonymous function. Where can we get that from? In functional Erlang, there are only three ways that names are bound - by closure, by parameter, or by local definition. We can't close over it, because the anonymous function isn't yet defined. We can't create a local definition, because the local scope is too narrow a scope for that. That leaves only one possibility - we need to pass the anonymous function to itself.

Foo = fun(AlsoFoo, N) ->
    case N of
        1 -> 1;
        _ -> N * AlsoFoo(AlsoFoo, N - 1)
    end
end.

Fact = fun(N) -> Foo(Foo, N) end.
OK, so we created a helper function - more on that in a minute. Foo (formerly Fact) now takes an extra parameter, which just creates another name for the current, anonymous function. Since we intend for that to be the same as Foo, we call it AlsoFoo. We know that Foo is a fun/2. Since AlsoFoo is supposed to be another name for Foo, then AlsoFoo must be a fun/2 as well. This means that, when we call AlsoFoo, we need to also tell it about itself - that is, we need to pass AlsoFoo along when we call AlsoFoo to recurse.

Now that leaves us to deal with the function Fact. Clearly, Fact needs to call Foo. We noted that Foo is a fun/2, so again, we need to call it with two parameters. The intent of the extra parameter to Foo was to be able to pass Foo to itself, so we do just that.

Believe it or not, we have just derived the concept behind the Y combinator. We have invented a scheme that allows an anonymous function to know itself, even in a language that doesn't directly support this. This is (I believe) the purpose behind the Y combinator. However, we're not yet done. There is still some cruft that we would like to eliminate. In particular, we hand-built the plumbing to route AlsoFoo around. We would like to use higher order functions to eliminate this. This is what the Y combinator does - it manages the plumbing of anonymous functions that refer to themselves.

In the next part, we will continue the derivation of the Y combinator in Erlang. Our goal is to eventually be able to write something like this:

Fact = y(fun(Self) ->
    fun(N) ->
        case N of
            1 -> 1;
            _ -> N * Self(N - 1)
        end
    end
end).
It's not perfect, but in a language that doesn't directly support anonymous function recursion, it's not too bad!

Monday, December 07, 2009

Even More Space Marine Painting

I've been slowly working on my Space Marines. It's taken a while, but they almost look like a unit. I think I've spent between 10 and 20 hours on them, but much of that was spent learning. Most of the major painting is done, and now it's time for touchups and details. For example, I spent some time on that rocket launcher to make it appear to be metal, painted red, and then worn. I think it's pretty convincing. I intend to do the same with that red bolter. The one that's not wearing armor needs a lot of work. Enjoy.

Tuesday, November 17, 2009

Standard algorithms and boost::ptr_vector

I did something bad the other day.

OK, I can't tell if it was bad. In another environment, it would have been bad, but since this was C++, perhaps it was OK. I was in the situation where I had a boost::ptr_vector, and I wanted to use a standard algorithm on it. Specifically, I wanted to use std::partition to separate the objects that were still "alive" from those that were "dead" (where alive and dead are domain concepts in our application). The complexity here is that ptr_vector is a crazy container.

Most containers deal with a specific type T. You add Ts to the container. Dereferencing an iterator gives you a T&. It's generally assumed that a container operates on a single type, and the standard algorithms make this assumption.

The ptr_vector, on the other hand, appears to be two containers at once. Semantically, it's analogous to a std::vector<managed_ptr_type<T> >. It is intended that, by adding a pointer to the ptr_vector, the ptr_vector takes ownership of the lifetime of the memory at the end of the pointer. So, it is a container of pointers. On the other hand, when iterating a ptr_vector, it appears that it is a container of Ts.

In my case, I wanted to rearrange my ptr_vector. In particular, I wanted to partition the pointers into those whose object was still "alive", and those whose object was "dead". Since a ptr_vector is semantically a container of pointers, it made sense that I should apply std::partition to the ptr_vector. However, ptr_vector::iterator removes a level of indirection: instead of iterating T*, it iterates T&.

In fact, ptr_vector doesn't seem to provide any ways to rearrange the pointers once they are put into the container. Sure, you can mutate the object on the end of the pointer. You could operate at that level. But there doesn't appear to be a safe way to treat the ptr_vector as a container of pointers.

Fortunately, ptr_vector provides a back door. Its iterators support a base() method, which will return an iterator over T* (instead of an iterator over T&). This allows us to treat the ptr_vector as a container of pointers, and to use standard algorithms to manipulate those pointers. Now, this is not without peril. While it seems to be OK to rearrange the pointers, it wouldn't be safe to change the set of pointers. I wouldn't trust using something like std::remove_if, because it might leave garbage in the container after it is done. The container might contain duplicate pointers. Some pointers might get dropped completely. If the container then goes out of scope, it will try to delete these pointers multiple times, which would be a bad thing. It might also fail to delete some pointers, because they were overwritten (and not preserved elsewhere in the container).

This whole thing felt like the best solution possible, while at the same time leaving a lot to be desired. I felt like I was violating the encapsulation of the ptr_vector. I suppose this is one of those cases for which they put in the base() methods on the iterators. Additionally, I don't see any clear way that they could do better. For example, I think an assumption of ptr_vector is that a given pointer only occurs inside it at most once. The standard algorithms don't necessarily respect this assumption; see my commentary on remove_if in the previous paragraph. The standard algorithms, in some cases, expect more freedom than ptr_vector can provide. This disconnect is unfortunate, but not without reason.

An important first step to helping with this problem would be to add methods to ptr_vector (and its siblings) that allow you to treat it as a container of pointers. You could add, remove, and re-arrange the container using these methods. In addition, they could maybe provide specializations of some of the standard algorithms for each container. This is difficult for third party developers to do, since the actual type of a ptr_vector::iterator is implementation defined. The boost guys can cleanly provide a specialization of std::partition for this kind of iterator, but I can't. Now, this isn't perfect. It would help with the standard algorithms, but not third-party algorithms. Still, it would be a great step in the right direction.

So, did I do something bad, or did I do something necessary?

Monday, November 02, 2009

Why Google Experience phones are pretty awesome

As Android has grown, devices fall into one of two major classifications. Some devices are so-called "Google Experience" devices (featuring the phrase "with Google" somewhere on the device). Other devices are, well, not Google Experience devices. What is the difference? I've had a hard time figuring it out.

I think that Google Experience phones are updated by Google itself, while the rest of the devices are supported by the phone's manufacturer. I have an original G1 (a Google Experience phone), and I've gotten prompt updates as each new Android OS version has been released. This is similar to the experience that iPhone users enjoy.

Some devices, such as the HTC Hero and the Motorola Cliq (and the HTC Magic in certain regions), are not Google Experience phones. These phones were released with heavily customized software (such as HTC's Sense UI or Motorola's Motoblur). These customizations, while attractive to some users, also make it much harder for the phone manufacturer to update to a new version of the base Android OS. Both the Hero and the Cliq shipped with Android 1.5, and I don't believe that there are announced plans to update either to 1.6 (or 2.0, for that matter).

At first, I thought that the notion of a Google Experience phone was silly. At the time, the Magic was launching on Rogers with Exchange support, and that somehow disqualified the phone as being a Google Experience device. I now understand that Google Experience really means "unforked code base". In order to add Exchange support, I suspect that HTC had to fork and modify the standard Mail app. While they were able to add a feature that people wanted, it really just makes these phones into some sort of mutant Android device. No thank you. Google should really make it clear to users that the Google Experience is a feature in and of itself.

Android, at this point, is a rapidly evolving platform. Google Experience phones seem to be the best way to keep up with this evolution. I was pleased when I heard a Verizon rep say that the Droid will be a Google Experience phone. Now they just need to release a T-Mobile US GSM version, and I'll be happy. Over time, Android evolution will slow down, and then it might make sense for a manufacturer to fork the Android code base. Maybe they would even be willing to contribute back to the core distribution. But, until then, I'm sticking with Google Experience devices.

Fixing hard disk clicking / aggressive head parking on Mac OS X

I recently bought a Western Digital Scorpio notebook hard drive to put into my 2007-vintage Macbook Pro. Everything seemed fine at first. However, as I used my laptop, I noticed that it would frequently make a quiet clicking noise. At first, I thought that I had gotten a bad disk. However, after doing a little research, it became clear that this is a common problem. This clicking is a "normal" operational noise - it is the sound of the heads parking.

People say that you should just get used to the noise. However, this blog post makes the argument that every one of these clicks is killing your hard disk. Some people claim that this is related to the sudden motion sensor that's built into most (if not all) Apple portables. However, this is a red herring. The disk still clicks even if it is sitting on a table. It is the hard disk's own built-in power management that is causing the head parking. The disk's SMART statistics record the number of head parking cycles. If you want to see this for yourself, you can use either this menu extra or this command line tool (MacPorts). You are looking for the Load Cycle Count value.

To explain the problem (as I understand it), modern hard disks have some responsibility to manage their power consumption. One manifestation of this is to spin down the platters and to park the read/write heads. The operating system can influence the time before the heads are parked by setting the "APM Level" of the drive to a value between 0x00 and 0xfe. Each drive manufacturer is free to interpret this value as they see fit. Mac OS X seems to set a default APM Level for all disks, and I think this value is 0x80. This is fine with Apple-shipped disks, but not necessarily for third party disks.

But wait! Perhaps you have bought the same kind of drive that Apple ships in their laptops. Are you safe? Not necessarily. Allegedly, Apple flashes their own firmware onto the the hard disks that they install at the factory. That's right, you're not running stock disk firmware. My suspicion is that this firmware changes the drive's interpretation of the default APM level. Recently, there was a firmware update from Apple that fixed this problem on disks that were shipped by Apple. Unfortunately, you can't use this utility to flash the new firmware onto a non-Apple drive.

Right, so the two solutions that I see are either:

  1. Write our own firmware
  2. Set a different APM Level value
Obviously, option 2 looks much more attractive. Bryce McKinlay wrote a utility called hdapm for doing just that. He even includes a launchd configuration to run hdapm as the system starts. One thing not mentioned in the readme is that you need to get the permissions of the launchd config file correct. The file needs to be owned by root (preferably root:wheel), and must not be group- or world-writeable. I also changed the config file a little; here is my version:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
 <key>Label</key>
 <string>hdapm</string>
 <key>ProgramArguments</key>
 <array>
  <string>/usr/local/bin/hdapm</string>
  <string>disk0</string>
  <string>max</string>
 </array>
 <key>RunAtLoad</key>
 <true/>
</dict>
</plist>

The biggest change is that I removed the "LaunchOnlyOnce" and "ServiceDescription" keys. I didn't see a reason to load it only once, and ServiceDescription seemed undocumented. This solution isn't perfect, however. First of all, hdapm uses a seemingly undocumented back door to adjust the APM setting. Ideally, we would actually spawn a daemon that continuously monitors and adjusts the drive's APM level. I'm not yet convinced that Mac OS X won't override my setting. Still, I have been running with this configuration for a couple of days, and things seem to be working well.

I have an open support issue with Western Digital to see if they have a fix for this issue. If there were some way that we could change the way the disk behaves under OSX, we could forego the additional software, which would be great. I've also heard of a utility called wdidle, which allegedly lets you write new idle settings to the hard drive. However, I was unable to find any official site for this software, so I'm not using it.

Finally, I would like to thank two people. First, Doug Aghassi's post really explained the symptoms that he was experiencing and put me on the right track for solving the problem. Thanks, Doug. Also, Bryce McKinlay was kind enough not only to write the hdapm utility, but also to answer the questions that I emailed to him. Thanks, Bryce.

Sunday, September 20, 2009

More Painting Space Marines

I have an update to my Space Marine painting. I've continued to shade the marines. After the previous coat of 1:1 Regal Blue to Ultramarine Blue, I added the following:

  • 1:2 Regal Blue to Ultramarine Blue
  • Ultramarine Blue
  • 2:1 Ultramarine Blue to Codex Grey

Each coat is painted in a slightly smaller area. The goal is to shade the model to match an imaginary light source. In my case, my light source is directly above the model. Here are the results:


I'm now only painting 2 marines. I'm going to finish them before starting others, so that I can improve on my technique for those later models.

I also started painting my Tyranid spores. This has been basecoated with Chaos Black spray, then painted with Blood Red, then washed with Chestnut Ink. I had tried Red Ink, but unfortunately, that color is too close to Blood Red.

Wednesday, September 16, 2009

Painting Space Marines

For some reason, I got an itch to paint some Warhammer 40k figures. I've been slowly assembling them over... I don't know, maybe 2 years. Hey, I have a lot of things that I do in my free time. Anyway, I finally got around to priming them the other day, and I've been painting like a crazy person since then.

Now, I should mention that these aren't the first figures I've painted. I had painted a squad of 5 marines that came in a box along with 6 paints and a brush. Here's one of them.

That was a good learning experience. This time, I have quality glue, basing material, spray primer, a variety of brushes, and lots of paints and inks. I'm posting some photos of various steps of the process. Hopefully, by putting them here, I will actually finish painting them.


This space marine has been assembled, based, and primed. The basing material is sand and rock, glued into place with regular white glue. The whole model is sprayed with a flat black primer, to help the other paint stick better.

This marine has had his armor painted with Ultramarine Blue. Actually, his feet are missing some paint, but I'll get around to that. Additionally, the black ground cover has been drybrushed to look like sand and rocks. I started with rocky sand, painted it black, then painted it to look like rocky sand again. Crazy? Probably.

This marine has been washed with a blue ink (which I think has been replaced with Asurmen Blue Wash). Ink is used because it settles in the crevasses and provides great depth.

This marine has had his armor panels painted with a 50/50 mix of Regal Blue and Ultramarine Blue. By leaving a slight gap around the edges, the blue wash peeks through the armor panels, and this looks great.

For those who don't know much about 40k, these figures are pretty small. Here's a comparison shot.

Now imagine trying to paint those eye lenses. Yeah, I'm not looking forward to it, either. Besides the eyes, I still have a lot to do. I plan to put another few layers of blue on the armor, paint the shoulder pad edges, drybrush the metal pieces, and so on. If anybody reads this and has feedback or suggestions, I'd love to hear from you!