Weird mood, and programming

I’m in a weird mood lately on a lot of levels. In the computing-for-fun world, I find myself wanting to get to know Python better, and uninterested in what’s usually my favorite language, Ruby.

I started learning Ruby and Python at about the same time, back in ’99 I think; at the time Ruby was cooler in some ways that mattered to me and I took a dislike to Python for not being Ruby.

I don’t know why, but I want to do stuff with Python now.

Of course, I’d really like to learn Haskell. But I think that it might be a bit beyond me. I like the idea of pure functional programming; my own programs even in imperative languages tend towards the purely functional. It just reduces confusion. But to learn Haskell well you have to learn about monads, and monads still make my head hurt. I get them in a vague basic way but when I try to get the details into my head it doesn’t work.

The same thing is true with continuations in Scheme, another language good for pure functional programming, though not to the same degree as Haskell. I understand the basic idea of what a continuation is, and I’ve even been behind a rewrite of a large chunk of our code at work in a continuation-passing style (long story why I did that but as far as I can tell it was the only non-insane way to accomplish what we needed to accomplish). But every time I try to actually play with Scheme’s “call-with-current-continuation” form it doesn’t work and I don’t understand why.

I sometimes like to imagine to myself that for a self-taught guy I’m a pretty sophisticated programmer, I like cool, obscure, conceptually superior languages (besides Ruby, Python, Haskell, and Scheme, I’ve messed around with Smalltalk, Common Lisp, Io, and even Prolog). Sometimes I manage to convince other people of that sophistication. But stuff like the monads and continuation thing makes me think maybe I’m not as sophisticated and cool a programmer as I imagine.

I look back on my life and there were a lot of times where I read a book or twelve on a topic and thought I really knew a thing or two about it but I look back on it and I really had just read some books. I used to think I really knew something about cognitive science, about linguistics (OK, I still think I really know something about linguistics), and going back farther about philosophy of language and literary criticism, semiotics and the like, and further back than that, I thought I knew a lot about Christian apologetics cause I read a lot of C.S. Lewis (and G.K Chesterton).

I don’t think of myself as an knowledgeable in any of those areas anymore, well, except maybe linguistics, a bit. I don’t read a lot about them or think about any of them anymore.

Maybe my conception of myself as knowing something about sophisticated programming topics is destined to fall by the wayside the same way.

Maybe I never will master Haskell or advanced Scheme techniques, and I never will do anything significant in programming outside my job hackin’ the Perl.

Maybe that’s OK.

I dunno, it’s just a weird mood.

3 thoughts on “Weird mood, and programming”

  1. They say learning is a process of controlled failure. I have enjoyed reading about programming languages, on your blog among other places, but I find that to become proficient I need to code in a language a lot. I have usually started by modifying existing code and seeing what happens. I’m sure there are people out there who can read some things about a language and pick it up right away, but for a lot of people like me, there seems to be no substitute for investing a lot of time.

    All of which is to say, in the words of Samuel Beckett, fail again, fail better. That’s learning.

    It would be neat to read about your practical use of continuations at work. This is a big deal in the Java community, because some people want it in the language, and lots of people don’t see how it would be distinctively useful.

  2. Well, we didn’t use continuations per se, because Perl doesn’t have them, but we used a continuation-passing style.

    In continuation-passing style, you take code like this:

    function f1(a) {
       x = f2(a);
       baz(x);
       // note that f1 doesn't return a value.
       // if it did this wouldn't work.
    }
    function f2(a) {
        x=foo(a);
        y=bar(x);
        return y;
    }
    

    Now let’s say that our problem is the function foo(), above. For whatever reason, we cannot possibly write foo() such that it returns a value.

    So how can we get the “return value” of foo() through the function bar(), returned as the value of f2(), into the body of function f1(), and then execute baz() on it??

    Well, we *can* rewrite foo so it accepts an anonymous subroutine as a second parameter, and executes it, passing it the value we would have returned if we could return a value.

    function f1(a) {
        continuation = function(b) {
            f3(b) {
        }
        f2(a, continuation);
    }
    function f2(a,continuation1) {
        continuation2 = function(b, continuation1) {
            y = bar(b);
            continuation1(y);
        }
        foo(a, continuation2);
    }
    

    You can see that in this style, we did not have to depend on foo() returning a value, but the code does exactly the same thing in every other way.

    Note that if we had to return a value from f1, this would fail, because the nature of the continuation-passing style is that functions *never return*. (Or at least they must be treated as if they never return).

    As for having continations in the language, well, imagine that you’re always in continuation-passing style but you never know it, and you never see the continuations, unless you use a special construct.

    In Scheme that construct is called “call-with-current-continuation” or “call/cc” With that you can call a function and feed it what the current continuation would be if you were writing in continuation-passing style.

    If I had call/cc, as I understand it, I could solve the problem of foo not returning values like this:

    function f1(a) {
       x = f2(a);
       baz(x);
    }
    
    function f2(a) {
        x = call_cc(
           function (continuation) {
              foo(a, continuation);
           }
        );
        y=bar(x);
        return y;
    }
    

    Now here’s the fun extra gravy part…

    The function we’re using, which is analogous to “foo” in my example here, actually returns values in several chunks, and executes the continuation once for each chunk.

    So we end up with the continuation being executed several times — and the functions enclosing it “returning” several times!

    In our application, the function analogous to “baz” sends data out through a web server; by calling it several times we stream the chunks of data which “foo” is emitting.

    That’s something you could not straightforwardly do without using either a continuation-passing style or a language that supports first-class continuations.

    Whoa. I may have just explained call/cc to myself by writing that. I’ll have to pick up a scheme interpreter and check. :)

    Did that make sense?

  3. Update: in Scheme, firing a continuation three times isn’t easy cause the continuation never returns to the point you fired it from. (Duh, continuations never return!) So it wouldn’t be trivial to use it to do what we did here.

    But I think I understand them a little better now.

Comments are closed.