15 comments

[ 3.2 ms ] story [ 46.1 ms ] thread
An alternative to 'if' that I like but havent seriously used before is <expression>.true? {block}. an example in ruby:

(3==3).true?{'Yes'} => "Yes"

(4==4).true?{'Yes'} => nil

using this implementation:

class Object def true? yield end end

class FalseClass def true? end end

class NilClass def true? end end

Sort of like how Smalltalk replaces 'if' statements with ifTrue: messages?
I'm only familiar with Ruby syntax, and not 100% fluent in it, but it seems to me like this kind of shortcut could make your code much less readable for not a whole lot of gain. I'm curious what the major benefit is over doing it 'the old fashioned way'.
I thought this was going to be about booleans from nothing at all:

    true = function(x,y){ return x; }
    false = function(x,y){ return y; }
    ifelse = function(x,a,b){ x(a,b)(); }
    not = function(x){ return x(false,true); }
    and = function(x,y){ return x(y,false); }
    or = function(x,y){ return x(true,y); }

    bool = and(not(true),or(true,false))
    ifelse(bool, 
      function(){ alert("true!") }, 
      function(){ alert("false!") }
    )
Amazing, isn't it?

It gets better.

Pairs:

    pair = function(x,y){ return function(f){ return f(x,y); } }
    fst = function(p){ return p(function(x,y){ return x; }); }
    snd = function(p){ return p(function(x,y){ return y; }); }
Unions:

    left = function(x){ return function(f,g){ return f(x); } }
    right = function(x){ return function(f,g){ return g(x); } }
Pairs combined with unions make lists:

    cons = function(x,y){ return left(pair(x,y)); }
    head = function(l){ return l(function(p){ return fst(p); }, function(n){ alert("Can't take head of nil"); }) }
    tail = function(l){ return l(function(p){ return snd(p); }, function(n){ alert("Can't take tail of nil"); }) }
    nil = right(false)
    isnil = function(l){ return l(function(p){ return false; }, function(n){ return true; }) }
    
    map = function(f,l){
      return ifelse(isnil(l),
         function(){ return nil; },
         function(){ return cons(f(head(l)),map(f,tail(l))); })
    }

    filter = function(f,l){
       return ifelse(isnil(l),
          function(){ return nil; },
          function(){ 
            return ifelse(f(head(l)),
                     function(){ return cons(head(l),filter(f,tail(l))); },
                     function(){ return filter(f,tail(l)); })
          });
    }
Isn't it neat how you can build everything, including conditionals, booleans, pairs and lists from functions?

Note that this code was not tested in any way, so it likely contains bugs.

You really can build everything out of anonymous functions, including all of arithmetic:

    zero = function(x,y){ return y; }
    succ = function (f) { return function (x) {return f(n(f(x)));};}
    one = succ(zero);
    two = succ(one);
Look up lambda calculus if anyone is interested.
The only problem then is, how do you do pred the inverse of succ? ;)
You need to construct integers with a tuple type, in lambda calculus its:

    pair = λ x. λ y. λ z. x. y. z
Or if you are willing to let pred(0) = 0 then you can use:

    pred = λ x. λy. λ z. x . (λ i. λ j. j. i. y (λ k. z) (λ k. k)
I recommend the Numbers Book ( http://www.amazon.com/Numbers-Graduate-Texts-Mathematics-Rea... ):

I just did a construction of the integers assuming either sets or arrays. I could equally have used your list definition.

http://pastie.org/1397123 and http://news.ycombinator.com/item?id=2030649

I've very tempted to combine your work with this and then go on to define rationals and then the reals. The reals would be very interesting since it would be a sequence that takes an epsilon and gets a rational number that is close enough. It's kind of crazy to think that all these real numbers are infinite cauchy sequences.

If I define a real as function(eps) { return some_rational; } then I could define it piece_wise and say function mult_real(a,b) { return function(eps) { return a(eps/2) * b(eps/2); } }

Building the reals out of lambda calculus would be cool. I don't think however that your definition of mult_real is correct. For example if a=b=10 and eps=2, then a(eps/2) x b(eps/2) could be anything between 9x9=81 and 11x11=121, whereas you'd want it to be between 99 and 101? How to fix this?
(comment deleted)
This seems to boil down to a preference for expressions over statements. It's easier to reason about the meaning of a value than a listing of commands, and more insightful to recombine subexpressions to make values than to recombine statements to get side-effects and void.
It's worth noting that these techniques also work in other languages - I've been doing this more and more often in the Python code I write.

If you aren't used to it, it looks a bit unusual (of course) but it makes for much cleaner, and therefore more maintainable, code.