Showing posts with label OCaml. Show all posts
Showing posts with label OCaml. Show all posts

Thursday, July 17, 2008

Groovy vs. F# Showdown - Side by Side Comparison

Ah, our old friend Maximum Segment Sum. Given a list of integers, find the highest sum of any set of adjacent integers. The list [ 1, 2, 3, -4] has an MSS of 6 (1 + 2 + 3). The solution is deceptively simple:

mss = max º sum* º (flatten º tails* º inits)

Briefly explained…

inits() returns all the initial segments of a list in order of increasing length. So the inits of [1, 2, 3] is [ [1], [1,2], [1,2,3] ]

tails() returns all the trailing segments of a list in order of decreasing length. So the tails of [1, 2, 3] is [ [1,2,3], [2,3], [3] ]

Calculating the MSS is as simple as taking the inits of a list, taking the tails of the result, find the sum of each element in that result, and return the maximum entry. Simple, right?

Solving this is a great way to practice functional programming, which I did using Groovy in Function Calisthenics a few months ago, and again last night using F#.

The F# and Groovy results can be seen side by side here: http://www.hamletdarcy.com/files/2008/FsharpVsGroovy.html (I suggest opening it up in a new window big enough so that the lines don’t wrap).

Which begs the question, “Why would you ever want to compare F# (or OCaml) to Groovy?”

Because it explores the answers to a few other questions:

Are dynamically typed languages more concise than statically typed ones? Maybe the comparison between Java and Groovy isn’t a fair comparison, because the results here show F#/OCaml being more concise.

How awful is the F#/OCaml syntax? You can make your own conclusion, but it might be worth spending a few hours with the language before pronouncing a victor. I personally have found the freedom from curly braces and good recursion support a Good Thing.

Do I want to give F#/OCaml a try? That’s kinda the point of writing a post about the language, isn’t it?

So here goes…

Conciseness – The F# version is shorter, there’s no denying that. You also don’t need to add any type information despite the fact that the language is statically typed and the IDE shows you compiler errors as they happen. Also, the F# libraries offer much better support for functional constructs. For instance, the map_concat function doesn’t exist in Groovy, so much of the Groovy code is simply reducing a List of Lists of Lists to a List of Lists. Groovy support for closures and collections is good, but check out the F# documentation and see all functions you wish you had. There is certainly a learning curve to understanding the map*, fold*, and reduce* functions, but I contend that it’s worth the time to learn the fundamentals of Computer Science, which these concepts can rightly be categorized as.

Also, concise List and Map (and Sequence!) creation using the [ a, b, c ] notation is a wonderful thing. But this is an issue with Java, not statically typed languages in general.

The Awful Syntax – Come on, is it really that bad? Sure there is a new set of libraries to learn… but you’re not exactly investing in learning the .NET libraries, just the F# ones. I don’t know a thing about .NET and this was fairly simple. It doesn’t even really rely on the .NET libraries in this example (under the covers it does because it’s implemented in a .NET language and provides interoperability, but that’s another matter). Ricky Clarkson explores having to learn a new syntax in his post “In Defence of (0/:l)(_+_) in Scala”, which includes a quote from David MacIver: "Optimising your notation to not confuse people in the first 10 minutes of seeing it but to hinder readability ever after is a really bad mistake." Exactly. Maybe its time we ditch the C++/Java syntax. It’s not that hard.

Giving F#/OCaml a shot – Let me be clear: Learning F# is not the same as learning .NET. There are plenty of directions online for running it under Mono in Mac/Linux, and the F# install comes with an install-mono.sh shell script. I got it to run on an EEE PC with Xandros Linux without much effort. And there have been plenty of “wow” moments learning F# including wondering how the heck the compiler knows about my types and the satisfaction of finally understanding what “('a -> 'b) -> 'a list -> 'b list” means (Hint: it is a type signature that takes a function and a list and returns another list).

And why would you not want to make this comparison? Groovy is not a functional language and doesn’t advertise itself to be. Closure/lambda support in Groovy is good, and enables a functional style, but it’s not quite a level playing field. A comparison of the languages in an Object Oriented style might well yield different results.

Anyway, give it a shot, my friends, give it a shot. Perhaps the sweet F# handout can shed some light: http://hamletdarcy.blogspot.com/2008/07/f-handout-available.html

Monday, July 7, 2008

Ruby.MN OCaml Video Available

Earlier this month I helped my friend Robert Fischer record his Ruby.MN presentation called "OCaml for Ruby-istas". The video has been edited and posted on his website.

Be sure not to pass by the Q&A, which was fairly interesting.

Thursday, July 3, 2008

Why Functional Programming?

Earlier this week Robert Fischer presented a session at the local Ruby group called "The OCaml Guide for Rubyists" (slides and video available soon). During Q&A, the last question was a simple, "Why?" Not a question so much as a lamentation. The real question being asked was, "Why in the world would you want to put up with horrible syntax, bizarre compiler errors, and unreadable type system REPL output just to accomplish the same thing I do regularly with a few lines of Ruby?" Robert's short answer was, "It will warp your mind," which might not have convinced anyone that OCaml was worth their time. I'd have given the same answer, though, only I would have made my response long, meandering, and possibly in need of a good edit. Welcome and let the journey begin!

I love programming because of the abstraction. Finding and removing repetition is a joyful act. In my C days (which were thankfully short, for both me and my customers), the abstraction came from carefully defined modules. The pinnacle of design was a finely crafted global library accessible to anyone who cared to include the proper header and debug the resulting link error. Entities and concepts were modeled in their own .c files, hierarchies and relationships were defined through directory structures, and exported abstractions made available in .lib files. Oh yeah, I really had this down, and I knew what programming was all about (including spending days finding memory leaks).

And when someone showed me C++ a lightbulb turned on. My basic unit of abstraction changed from the library to inheritence, and my mind was warped. Holy cow! Modeling everything as parent-child relationships opened up a whole new realm of software design. Everything is an object, and everything has shared code in its parent type. I could get wide-spread behavior changes in my program simply by changing some code way up high in the type hierarchy. And the way to do this was multiple inheritance, right? All my systems looked like inverted pyramids... there was one core implementation class with dozens of parent classes spread out above it. Genius, or so I thought.

And then I found out about the Gang of Four Design Patterns. In an act of supreme hubris, I remember arguing with the team architect about the definition of an interface. I firmly believed an interface was an interaction library, like the Win32 Application Programming Interface. I had no idea why anyone would create a parent type with no implementation, and thank you Gavin Ford (wherever you are) for handing me that book and telling me to bugger off. With design patterns and a new found mandate to prefer composition over inheritance, I was off and running with a primary unit of abstraction: the class. Mind warp #2, for those counting. I could never go back to C now.

And for a long time it stopped. Java and its awesome toolset let me create reams and reams of code all structured to one design pattern or another. And the Java libraries contained many of the patterns, so it must be the right way to design software. Java enabled me to overuse patterns, and I slowly realized that they weren't an end to themselves... but this didn't really qualify as a mind warp despite the hundreds of Internet posts proclaiming the death of patterns due to closures and dynamic typing.

People moved on. Some moved on to embrace meta-programming as the next mind warp. But is this really a means of abstraction? Does meta-programming allow you to construct more general and reusable structures? From a client perspective, writing code against ActiveRecord and GORM is certainly a time saving shortcut. But in my experience, meta-programming exposes you (as a writer) to a very low level of the language. Method dispatch, metaclasses, caching closures... this doesn't feel very abstract. It feels reusable as long as method calls and database columns and xml schema all line up. (Quick quiz, what's the difference between programming by convention and coincidence? One is the next big thing and the other is warned against in the Prag book.) But is metaprogramming layer of abstraction that allows you to specify behavior in a more general way? Perhaps not. It's a mind warp, but a very implementation specific warp.

Another direction people move towards is device development, most notably the iPhone. I spent waaay too long programming mobile devices and I cringe at the thought of downloading some iPhone SDK. Honing my programming skills towards learning a device API and graphics library is simply the wrong direction. It is a step closer to the hardware, the implementation, and a step away from a higher level of abstraction. No thanks. I'm quite skeptical that new software ideas will be the product of anyone moving into the device development space. Rediscovering pointer arithmetic and reimplementing existing frameworks on a smaller footprint seems a more likely outcome. Neither of which sounds appealing.

So I'm here to say that mindwarp #3 is discovering the function as the basic unit of abstraction. Jaw-droppingly beautiful abstractions and generalizations can be created out of just functions. You can rediscover the usefulness of partial functions and currying, which were techniques created in the 1800s. You can be in the direct lineage of Alan Turing, who used higher order functions in the 1930s to define his theoretical Turing Machine in his paper "On Computable Numbers, with an Application to the Entscheidungsproblem." And you can finally understand recursion in a deep and intuitive way, and you'll feel like you've looked into the abyss and somehow come back to tell everyone else about it. And maybe, just maybe, you can explain to me what a freakin' monad is.

And maybe (just maybe!) Ruby isn't the language to try this in. Ruby is awesome for a lot of things. Just check out how fast and furious one-line responses to Cedric's challenge appeared. The fact the Ruby solutions are denigrated as "a dime a dozen" says something about how fast and easy the language is to work in. But how easy are function objects in Ruby? Does it take 5 pages of text to fully explain the fine points of procs and blocks? I've been told several times to stop trying to do FP in Groovy because a better functional programming language will more easily reveal the beauty and simplicity of functions. You want to concentrate on the FP concepts and eliminate all the noise of how the language implements functions. Non-functional languages contain imperative and procedural noise that will distract you from having your mind warped. Just pick a more functional language.

And that is my answer of why Rubyists should learn OCaml: Your mind will warp when you discover functions are the next unit of abstraction, and OCaml's sort-of FP purity will have your mind warping sooner than it would with other languages.

Thus concludes my contribution to a well covered topic. Interested readers may wish to read the original Why Functional Programming Matters and Raganwald's thoughts on the same.

Thanks!