I think it's good for me (the sort of person who traditionally holds his tongue for fear of making a fool of himself-- ie, the sort of person that's impossible to talk with, only to) to continually expose my thought process because it forces me to quantify and justify what it is I'm reaching for. (For what my opinion is worth, I'm pretty firmly in Jens' s camp, except replace "Objective C" with "C" because we work with different platforms. But I think it's good for me (even though I'll likely end up an applications-level programmer) to keep expanding my understanding...)
More OCaml wanking, then: dove into actually using imperative features in a useful way and into the module/compiler system. Rewrote the dijkstra function to a (much faster, I imagine) array/hash-based one, wrote a getopt-like parser for argv that reorders arguments (which, now that I think harder about it, could have easily been done totally functionally). Made modules and libraries, played with the profiler, which is hella cool: it emits your source code tagged up with comments on how often different bits were ran. You can also generate (only x86 and sparc, apparently) binaries that will run through gprof, which was pretty impressive. Also, I managed to write a program top to bottom that compiled the first time! (This isn't so exciting with most languages, but OCaml's syntax is still really hard for me.)
I'm still thinking a lot about types. I had some (linguistic) semantics homework that included describing the signature of adverbs (used in a specific way, modifying verb phrases), and the first thing I thought was, "This has to map from VP's type to VP's type, and VPs are lists. That pretty much means it's gotta be 'filter'."
There's an OCaml browser that feels sorta like the Smalltalk* browser in that you have modules and functions displayed in a NeXT-style file browser and a builtin editor.
One interesting difference that took me a while to grasp is that it only displays the signatures (to my mind "prototypes", but I'm very much a C programmer) of functions and not their bodies. There's a button available that brings up the relevant source code, but as I used it I found I rarely needed to look at the code to know what the functions did. The idea was introduced in my PL class as "theorems for free": if you have a function that takes pairs of type (alpha,beta) and produces pairs of type (beta,alpha), then that function must be the swap function... as long as the language doesn't have side effects! Exceptions, printing, modifying globals, etc. can all ruin that dream, of course, but when you're looking at a class library they generally try avoid those just so you can get that kind of guarantee. (And back to my linguistics homework: no side-effects there, hopefully!)
Even the operation of more complicated functions (like List.map or List.reduce) can be deduced from their types (if you have `a list -> (`a->bool) -> `a list, what else can it be other than filter?) and the rest is pretty much disambiguated by their name.
I suppose this isn't really groundbreaking-- I use lots of C libraries whose API doc
is just reading the header file-- but it was different than what I'm used to with at least Smalltalk. And in any case, this paragraph is a nice conclusion that wraps everything up back around to the beginning of this post.
* or at least Squeak, but it would seem that would be based on Smalltalk's design... my memory of Smalltalk is incredibly vague, though I'm feel like I played with it sometime in middle school. I know I had a friend in band class (hah) who was really into it.