Metacircus by Howard Yeh

Words Are But Shattered Mirror of Thoughts

Lispy Abuse of Ruby: Local Functions

If Ruby were a person, the court would put a restraining order prohibiting my appearance in her vicinity (I somehow think of Ruby as a girl). But since there’s now law against it, I am free to bend and abuse her for my devious pleasures.

Functional languages like Lisp and Haskell make it easy to define highly granular scopes. It’s possible to define a local function, and restrict its scope to any arbitrary chunk of code. In Lisp (Scheme), it looks like:

(let ((fun1 (lambda () 1)))
  (list (fun1) ; first element
        (let ((fun2 (lambda () 2))) (fun2)) ; second element
        ))
        
;; => (list 1 2)

In this example, fun1 is a helper method for building the list. And fun2 is even more restrictive in scope. fun2 is only available for building the second element of the list.

Closer to home, you can do the same in Javascript:

(function () {
  function fun1() { return 1 };
  return [fun1(), (function () {
    function fun2() { return 2 };
    return fun2();
  })()];
})();

Unfortunately though, we need to create one anonymous function each time we want a scope [1].

In Ruby, this is as close as it gets,

def test
 fun1 = lambda { 1 }
 fun2 = lambda { 2 }
 [fun1.(),fun2.()]
end

The scoping isn’t right. And so clumsy. How can we do better?

Bwahahahahahahahaha~~~~~

def flet(&block)
  mod = Module.new
  mod.extend(mod)
  mod.module_eval(&block)
end

This allows you to do something like

flet do
  def fun1
    1
  end
  [fun1,flet do
     def fun2
       2
     end
     fun2
   end]
end

Exercise: how do you make flet nestable? As in,

flet do
  def fun1
    1
  end
  flet do
    def fun2
      2
    end
    [fun1,fun2]
  end
end

Note that in this example fun1 is called in the scope of the inner flet.

Leave your answer in the comments ; )


[1] It looks much better in CoffeeScript:

(->
 fun1 = -> 1
 [fun1(),(-> (fun2 = -> 2); fun2())()]
)  

OK… maybe not much better.

If you like my writing you should follow me on Twitter.