"Thinking in types" or "The mind of a programmer"

Apr 27, 2007 16:38

In a previous post, pozorvlak and I wondered about the differences between the thought processes that goes into writing good static code, and those that go into good dynamic code. We figured that there wasn't a lot out there to help dynamic programmers get the hang of static style thinking, so what follows is a simple little toy example, solved in what I ( Read more... )

thought processes, hacking, typing, haskell

Leave a comment

anonymous April 27 2007, 17:56:27 UTC
Found this off the Planet Haskell blogs. Being fairly new to FP myself, I still don't think much in types, and hadn't really thought of starting with a matching type first then filling in the blanks. I think other beginners might really like some elaboration on the thought process of matching the types up; it took me a few moments to realize first that split was point-free, that split was matching the types from the right, that the 'y' parameter was needed to fill in the second parameter of foldl to make the types perfectly fit, etc.

Then there was the natural tendency for me to want to make the polymorphic type names correspond to each other; things were made easy due to your declaration of split looking like:

split :: b -> [b] -> [[b]]

Which made matching it up with foldl easy by just substituting [[b]] for a and not having to touch b. Whereas the natural tendency would be to write:

split :: a -> [a] -> [[a]]

Thus making the substitution in one's head a little trickier for a beginner when looking at foldl. I find that writing my own types using x/y/z for type parameters is easier.

There's precious few "thinking in types" tutorials that are actually accessible to beginners, so reading this was quite eye-opening. Keep it up! :)

Reply

anonymous April 27 2007, 18:26:41 UTC
Sorry that wasn't as clear as I wanted to make it... I should say I use x/y/z in my types when I'm looking for a match, and then I convert them back to a/b/c afterward. As for "matching from the right", that is to say that split's type matches the right side of foldl.

I also discovered hoogle, which looks fantastic for finding matching types .. though I should probably get good at doing it in my head first. Still, I can't wait for an IDE with built in hooglitude :)

Reply

totherme April 27 2007, 18:45:54 UTC
Hoogle is fantastic - and I use it often :)

I think the closest we have to and IDE with built in hooglitude is GHCi on Acid as mentioned here. There's also vim integration, if you want it :)

Reply

totherme April 27 2007, 18:36:54 UTC
Thanks - it's nice to know that this stuff is useful to someone :)

I think other beginners might really like some elaboration on the thought process of matching the types up; it took me a few moments to realize first that split was point-free, that split was matching the types from the right, that the 'y' parameter was needed to fill in the second parameter of foldl to make the types perfectly fit, etc.

split sort of came out point free once I'd made the connection between its type signature and the fold one... First, I'll mention the "matching from the right":

In general, I think if you're writing function f such that f :: SomeInputs -> SomeMoreInputs -> AnOutput and you happen to have a function g lying around with type g :: SomeDifferentInputs -> AnOutput then g is a potential candidate for being the last thing called in your definition of f.

As for being point free, if that g has the type g :: SomeDifferentInputs -> SomeMoreInputs -> AnOutput then there's a chance you can make your f point free on SomeMoreInputs - if those latter inputs that g needs happen to coincide with what you're expecting in f. If that's the case, you've changed the nature of the problem - you don't have to write f :: SomeInputs -> SomeMoreInputs -> AnOutput anymore - you just need to write some (simpler) function h :: SomeInputs -> SomeDifferentInputs.

There's nothing to stop you from doing all this matching from the left though - if g happened to be of type g :: SomeInputs -> SomeMoreInputs -> IntermediateType and you can see that it'd be easy to write h :: IntermediateType -> AnOutput, then your definition of f is
f = g.h

Hm - I hope that didn't just get a whole lot less clear in the more general case ;) Maybe I should think about writing a concrete example of writing a function by matching types from the left?

Oh yes - you're right - I did choose the letter "b" in the type signature of split so as to make the connection to the type of foldl a little more obvious. I think this is similar to when you're writing untyped functions or procedures and you choose to make the parameter names match up:

//Forward declarations
void setBrushColour(colour);
void drawCircle(coords, radius);

void drawPrettyCircle(coords, colour, radius) {
setBrushColour(colour);
drawCircle(coords, radius);
}

...the fact that the parameter names match up makes the whole thing prettier, and easier to read and understand in a forum like this. But, once you've got a bit of practice in the language, third party libraries that use different names for the parameters in their documentation (position and size, perhaps) won't phase you at all.

Thanks for the feedback :)

Reply

pozorvlak April 27 2007, 22:24:45 UTC
Excellent, glad it's not just me that finds this stuff hard :-)

Reply


Leave a comment

Up