Created
September 21, 2012 09:13
-
-
Save gnarmis/3760519 to your computer and use it in GitHub Desktop.
Experimenting with bastardized functional-ness in Ruby
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#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