Skip to content

Instantly share code, notes, and snippets.

@rbxbx
Created September 28, 2012 21:44
Show Gist options
  • Save rbxbx/3802234 to your computer and use it in GitHub Desktop.
Save rbxbx/3802234 to your computer and use it in GitHub Desktop.
Notes from strangeloop 2012 "The Higher Order Rubyist" talk

The Higher Order Rubyist

BUILT-INS

Obviously, when looking to program functionally in a given language, the first place one should look is within the language itself. Luckily, while not a Functional language (by any stretch of the word), Ruby has many facilities that enable it to act like one.

  • Enumerable map/reduce/filter/ and many of your other favorite HOFS destructuring variable assignment in block args via (_, _, foo)
  • lambdas, blocks, procs function objects, sort of. Lambdas & Procs can act as closures (are able to capture things within their lexical scope and carry them along, statefully)
  • Object.method(:identifier) unbind methods from objects, however you'll have to unbind it and rebind it to change the receiver (ie: if there are any references to self within the method body)
  • curry via the Proc#curry method Ruby 1.9 introduced facilities for currying and partially applying Proc objects
  • callcc (CPS?) Ruby supports continuations via callcc (whose name was even lifted from Scheme)... And they also fixed most of the horrible memory leaks from old versions... but it looks like it may ultimately be deprecated :(
  • Recursion/TCO in ruby 1.9.2 (or via compile-time flags) RubyVM::InstructionSequence.compile_option = { :tailcall_optimization => true, :trace_instruction => false } TOOLS
  • Hamster efficient immutable thread-safe lazy well documented/tested two years old supports all standard ruby data structures and then some
  • Stunted Something of a toolkit for programming with Ruby in a Functional style. I'm sure you could use this for production code... But I'm not sure that you should. That said, perhaps it's a playful exploratorium. I wouldn't be surprised if this got enough attention and was allowed to stay in flux for a while (ie: api/breaking changes) that a useful set of tools could definitely come out of. The code is pretty clean and pretty tested, but begins to push the limits of what Ruby wants to do, and it shows. That said, if you're comfortable reading Rails source, you'll be fine and/or relieved :) Well tested, most documentation lives in the wiki and example code.
  • Ruby#Facets A modular set of common functionality -- ie: there's a function for that Ever have that nagging feeling that the utility function you just wrote seems like a pretty clear pattern that surely someone else must have needed before? If you're an experienced programmer there's a good chance that you have (and perhaps you even keep some of these around for later use in some form or another). Essentially, Facets is a collection of just that. Especially exciting to those of us in the Functional realm would be the addl methods added to utility. All your favorites are there! including: frequency, array-to-hash, hash-to-array, mash, zip_map, etc! Lazy-ish sequences (deferred evaluation) Some of this is older and has been merged into Ruby 1.9. Most everything is tested/documented and well written. Definitely good source to read to learn about rolling your own enumerable-esque methods.
  • Celluloid (not strictly FP, but actors) For fans of Erlang, we have Celluloid, which is a production ready Actor implementation which works on top of most Ruby implementations. While not strictly functional, it's a nice way of handling concurrency in Ruby.
  • Monads -- So Monads are essentially, simply, a pattern, to be used in (most) any language. While Ruby doesn't ship with facilities/syntax/sugar to make working with Monads easy/recognizable/formally specified, a few people have taken stabs at such a thing, most notably Raganwald's Ick or Aanand Prasad's do_notation, although the first is largely unmaintained and the latter is incomplete. You probably shouldn't use either in production unless you really know what you're doing, in which case you probably wouldn't. They are neat hacks though :)

TECHNIQUES

Why bother?

Why stay with Ruby? Honestly, this is not a talk aimed to convince non-rubyists to migrate to Ruby, or rather at least not those already programming a functional or functional-ish language that they're happy with. Largely my goal was to sharpen the tools available to current Rubyists caught in the imperative mindset. That said, maybe you functional buffs need a better scripting language in your toolkit that supports a lot of the patterns you use on a daily basis. We in the Ruby community would love to have you come by and maybe stay a while, have some tea, and share your ordained wisdom with us ;)

We may have stupid haircuts and lack in scientific rigor from time to time (Thanks Rails!)
But we also have a pretty damn diverse communtiy full of awesome people you might not meet
at your next Haskell or Qi meetup (Thanks Rails!)
  • legacy There are reasons I stay with Ruby, despite my budding alliances with functional languages. It's a fantastic language for a variety of tasks, capable of very expressive programming in a style that would be familiar to people of a variety of different backgrounds (in large part due to the language is sort of a baby of Perl, Smalltalk, and Common Lisp). There are many many places that I could go into and be paid to program in a functional style due to their usage of Ruby. So on, so forth. The same could be said of Java and C++, but you've seen FunctionalJava and C++11 lambda syntax, right? Yeah.
  • community The community is fantastic. And they're starting to come around to FP as well :)

Why shouldn't I do this? Some people might get a little up in arms over it. There's a good chance they're just afraid of what they don't know though and don't know better how to act... introduce these techniques slowly and go out of your way to educate your coworkers to the benefits. Make sure everyone knows this stuff isn't black magic. Remember, you were a beginner to this one time as well. Some of these techniques will have perfomance implications over their non-functional counterparts, but the lovely thing about declarative programming is that the optimization of such things is left to the compiler/interpreter/etc so it's not on you to solve. Not to mention that you can always go back and drop to lower level constructs when necessary... after copious profiling ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment