Skip to content

Instantly share code, notes, and snippets.

@gnarmis
Created September 21, 2012 09:13
Show Gist options
  • Star 2 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save gnarmis/3760519 to your computer and use it in GitHub Desktop.
Save gnarmis/3760519 to your computer and use it in GitHub Desktop.
Experimenting with bastardized functional-ness in Ruby
#ruby1.9.3
def defn name, &b
Object.send :define_method, name, &b
end
# this also works (surprisingly), albeit with a warning
# def defn name
# Object.send(:define_method, name)
# end
(defn (:a) {|x, *y| print x; print y})
(a 1, 2, 3, 4) #=> 1[2,3,4]
(defn (:sum_of_squares) do |x, y|
x*x + y*y; end)
defn (:sum_of_squares) {|x, y|
x*x + y*y
}
(puts (sum_of_squares 1, 2)) #=> 5
# it doesn't need to be a method
(defn (:foo) {23})
foo == 23 #=> true
# want let? As per http://www.opensourcery.com/blog/zack-hobson/objectlet-ruby-0, this is all that's needed:
class Object
def let
yield self
end
end
((2).let {|x| puts x+1}) == 3 #=> true
# Here's something else that works kinda like `let`.
# You can do any kind of destructuring you want, of course.
def with coll, &fun; coll.map &fun; end
with [[1,2]] {|x,y| puts x+y} #=> 3
# execute an array of lambdas one after another?
def body *args
args.each {|e| e.call}
end
(body (lambda {print 1}), (lambda {print 2})) #=> output: 12
# map as a "top-level" function. This maps some lambda to an array,
# passing each element to the lambda to call.
def map fun, coll
coll.to_a.collect {|i| fun.call(i)}
end
(map (lambda {|x| x+1}), [1,2,3]) #=> [2, 3, 4]
hash = {:yes => 1, :no => 0}
(map (lambda {|x| hash[x]}), [:yes, :no, :yes]) #=> [1,0,1]
# reduce as a "top-level" function
def reduce fun, val=nil, coll
return coll.to_a.reduce(fun.to_sym) unless val
return coll.to_a.reduce(val) {|sum, i| sum.send fun.to_sym, i} if val
end
(reduce :+, [1,2,3]) #=> 6
(reduce :+, 3, [1,2,3]) #=> 9
# piping a single input through a bunch of functions
# (yay, composable functions!)
def pipe args, *methods
methods.reduce(args) { |a, m| send(m, a) }
end
def foo(data)
data[:a] += 1
data
end
def bar(data)
data[:b] += 10
data
end
hash = {:a => 0, :b => 0}
(pipe hash, :foo, :bar) #=> {:a=>1, :b=>10}
# good old filter is also pretty easy to define
def filter pred, coll
coll.to_a.select &pred
end
(filter ->(x){x.even?}, [1,2,3]) == [2] #=> true
# a function to call a lambda (forcing it to execute)
def call b; b.call; end
saved = lambda {puts "did I get called?"}
#=> #<Proc:blahblahblah (lambda)>
(call (lambda {puts "I got called!"; reduce :+, [1,2,3]}))
#=> output: I got called!\n => 6
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment