Skip to content

Latest commit

 

History

History

programming_with_nothing

Folders and files

NameName
Last commit message
Last commit date

parent directory

..
 
 
 
 
 
 
 
 
 
 
 
 

Programming with Nothing

This chapter includes an implementation of FizzBuzz written with just procs:

$ irb -I.
>> require 'programming_with_nothing'
=> true
>> MULTIPLY[THREE][FIVE]
=> #<Proc (lambda)>
>> to_integer(MULTIPLY[THREE][FIVE])
=> 15
>> to_array(RANGE[FIVE][TEN]).map { |p| to_integer(p) }
=> [5, 6, 7, 8, 9, 10]
>> to_array(MAP[RANGE[FIVE][TEN]][MULTIPLY[THREE]]).map { |p| to_integer(p) }
=> [15, 18, 21, 24, 27, 30]
>> to_integer(FOLD[RANGE[FIVE][TEN]][ZERO][ADD])
=> 45
>> results = to_array(SOLUTION)
=> [#<Proc (lambda)>, #<Proc (lambda)>, #<Proc (lambda)>, #<Proc (lambda)>, #<Proc (lambda)>, …]
>> results.each do |p| puts to_string(p) end; nil
1
2
Fizz
4
Buzz
Fizz
7
⋮
94
Buzz
Fizz
97
98
Fizz
Buzz
=> nil

Watch this video for more explanation.

There’s also an implementation of the call-by-value small-step operational semantics of the lambda calculus, along with a parser for Ruby-style lambda calculus expressions:

$ bundle exec irb -I.
>> require 'treetop'
=> true
>> Treetop.load('programming_with_nothing/lambda_calculus/lambda_calculus')
=> LambdaCalculusParser
>> require 'programming_with_nothing'
=> true
>> one = LambdaCalculusParser.new.parse('-> p { -> x { p[x] } }').to_ast
=> -> p { -> x { p[x] } }
>> increment = LambdaCalculusParser.new.parse('-> n { -> p { -> x { p[n[p][x]] } } }').to_ast
=> -> n { -> p { -> x { p[n[p][x]] } } }
>> add = LambdaCalculusParser.new.parse("-> m { -> n { n[#{increment}][m] } }").to_ast
=> -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }
>> expression = LCCall.new(LCCall.new(add, one), one)
=> -> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[x] } }]
>> while expression.reducible?; puts expression; expression = expression.reduce; end; puts expression
-> m { -> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][m] } }[-> p { -> x { p[x] } }][-> p { -> x { p[x] } }]
-> n { n[-> n { -> p { -> x { p[n[p][x]] } } }][-> p { -> x { p[x] } }] }[-> p { -> x { p[x] } }]
-> p { -> x { p[x] } }[-> n { -> p { -> x { p[n[p][x]] } } }][-> p { -> x { p[x] } }]
-> x { -> n { -> p { -> x { p[n[p][x]] } } }[x] }[-> p { -> x { p[x] } }]
-> n { -> p { -> x { p[n[p][x]] } } }[-> p { -> x { p[x] } }]
-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }
=> nil
>> inc, zero = LCVariable.new(:inc), LCVariable.new(:zero)
=> [inc, zero]
>> expression = LCCall.new(LCCall.new(expression, inc), zero)
=> -> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[inc][zero]
>> while expression.reducible?; puts expression; expression = expression.reduce; end; puts expression
-> p { -> x { p[-> p { -> x { p[x] } }[p][x]] } }[inc][zero]
-> x { inc[-> p { -> x { p[x] } }[inc][x]] }[zero]
inc[-> p { -> x { p[x] } }[inc][zero]]
inc[-> x { inc[x] }[zero]]
inc[inc[zero]]
=> nil