Ch6
method
singleton method
1 2 3 4 5
| o = "some object" def o.echo puts self end o.echo
|
alias
alias <new> <origin>
take an example:
1 2 3 4 5 6 7 8 9 10
| def foo end alias real_foo foo def foo real_foo end
|
default argument
- default arguments must be adjacent
- left-to-right assign
block as argument
1 2 3 4
| def foo(.., &b) b.call(..) end
|
- block argument and real block cannot be given at same time
proc as argument
1 2 3 4 5 6 7
| p = Proc.new {..} def foo(.., p) end def bar(.., &b) end foo(.., p) foo(.., &p)
|
using &
- method symbol has
.to_proc
to Proc object
&
before Proc object make it applicapable by iterator, lst.map &:upcase
&:sym
= &:sym.to_proc
in invocation
Proc & Lambda
- both
is-a
Proc
- == only via
dup,clone
create proc
from block:
or:
Proc.new
- lambda
succ = lambda {|x| x+1}
succ = ->(x){ x+1 }
f = ->(x,y; i,j,k) {..}
or f = -> x,y; i,j,k {..}
arg: x,y; local-var: i,j,k (minial lambda: ->{}
)
invoke
for both proc and lambda:
diff
return
proc:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| def makeproc(msg) p = Proc.new { puts msg; return } puts "return from proc" p end def test puts "enter method" p = makeproc "enter proc" p.call puts "exit method" end test
|
lambda:
1 2 3 4 5 6 7 8 9 10
| def makelambda(msg) .. end def test .. end test
|
break
- proc: as block break out whole iterator
- lambda: normal break, only make sense within enclosing loop or iteration
arguments
- proc: no number match, auto pack/unpack, life easier
- lambda: exact match, no auto splat
closure
- proc and lambda are closures
- closure possess the copy of local context when created
- alter via binding:
def foo(n); lambda {..}; end
- then
f2 = foo(2)
- f2 can altered to
eval("n=3", f2)
or eval("n=3", f2.binding)
(complete form)
method object
1 2 3
| m = 0.method :succ m.call or m[]
|
not closure
unbound method object:
1 2 3 4
| unbound_plus = Fixnum.instance_method "+" plus_2 = unbound_plus.bind 2 plus_2[2] plus_3 = plus_2.unbound.bind 3
|
functional
enumerable as example
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| module Functional def apply(enum) enum.map &self end alias | apply # some_method <= enumerable: .. as reduce def reduce(enum) enum.inject &self end alias <= reduce end # mixin to Proc & Method class Proc; include Functional; end class Method; include Functional; end # take standard deriv as example stddev = -> a { sum = -> x,y { x+y } mean = (sum <= a) / a.size # if you want to make it lambda, should ensure it can refer `a` in invoking deriv deriv = -> x { x - mean } square = -> x { x*x } Math.sqrt( (sum <= square|(deriv|a)) / (a.size - 1) ) } stddev[[1,2,3,4]] # => 1.2909944487358056
|
compose
1 2 3 4 5 6 7 8
| def compose f if self.respond_to?(:arity) && self.arity == 1 -> {|*args| self[f[*args]]} else -> {|*args| self[*f[*args]]} end end alias * compose
|
partial apply
1 2 3 4 5 6 7
| def apply_head(*first); -> *rest { self[*first.concat rest] }; end def apply_tail(*last); -> *rest { self[*rest.concat last] }; end alias >> apply_head alias << apply_tail g = f >> 2 g = f << 2
|
memorize
1 2 3 4 5 6 7 8 9 10 11 12 13
| def memoize cache = {} lambda {|*args| unless cache.has_key?(args) cache[args] = self[*args] end cache[args] } end alias +@ memoize
|
example:
1 2 3
| factorial = ->x {..}.memorize or +lambda {|x|..} factorial = ->x {..}; cached_f = +factorial
|
with symbol
1 2 3 4 5
| alias [] bind String[:reverse]["hello"][]
|