Module: LambdaDriver::Liftable

Included in:
Method, Proc, Symbol
Defined in:
lib/lambda_driver/liftable.rb

Constant Summary collapse

DEFAULT_CONTEXT =

This is a default context-function. default behaivior is compose function with checking g(x) is mzoro

if g(x) is mzero, it does not call self and return g(x), otherwise returns f(g(x)).

mzero means the object is nil or emtpy

hash = {:a => "foo"}
f = lambda{|y| y.length }
g = lambda{|y| hash[y]}
h = f.compose_with_lifting g
h.(:a) # => 3
h.(:b) # => nil (it does not called f)
LambdaDriver::Context[:maybe]

Class Method Summary collapse

Instance Method Summary collapse

Class Method Details

.included(klass) ⇒ Object



122
123
124
125
# File 'lib/lambda_driver/liftable.rb', line 122

def self.included(klass)
  klass.send(:alias_method, :<=, :compose_with_lifting)
  klass.send(:alias_method, :ymsr, :lift)
end

Instance Method Details

#>=(g) ⇒ Object



118
119
120
# File 'lib/lambda_driver/liftable.rb', line 118

def >=(g)
  g.to_proc.lift(lambda_driver_liftable_context).compose_with_lifting(self)
end

#compose_with_lifting(g) ⇒ Object

Compose self and given function on the context-function. The context-funciton is passed by ‘lift` method.

This method returns composed funciton like bellow.

lambda{|args|  context.call(self, context.call(g,*args) }

For example, set context-function that logging the result.

hash = {:a => "foo"}
f = lambda{|x| x.length}
g = lambda{|y| hash[y]}

ctx = lambda{|f,x|
  res = f.call(x)
  puts "result -> #{res}"
  res
}

lifted = f.lift(ctx)
h = lifted.compose_with_lifting g

h.(:a)
#=> result -> foo
#=> result -> 3
#=> 3

if context-function does not given, default behaivior is compose function with checking g(x) is mzoro

if g(x) is mzero, it does not call self and return g(x), otherwise returns f(g(x)).

mzero means the object is nil or emtpy

hash = {:a => "foo"}
f = lambda{|y| y.length }
g = lambda{|y| hash[y]}
h = f.compose_with_lifting g
h.(:a) # => 3
h.(:b) # => nil (it does not called f)

This method is aliased as ‘<=`.

f <= g # => f.compose_with_lifting(g)


50
51
52
53
54
55
56
57
58
59
60
61
62
# File 'lib/lambda_driver/liftable.rb', line 50

def compose_with_lifting(g)
  if @lambda_driver_lifted
    ctx = @lambda_driver_liftable_context
    self.compose(g).tap{|f|
      f.instance_eval do
        @lambda_driver_lifted = true
        @lambda_driver_liftable_context = ctx
      end
    }
  else
    self.lift(DEFAULT_CONTEXT).compose_with_lifting(g)
  end
end

#lambda_driver_liftable_contextObject



114
115
116
# File 'lib/lambda_driver/liftable.rb', line 114

def lambda_driver_liftable_context
  @lambda_driver_liftable_context || DEFAULT_CONTEXT
end

#lambda_driver_lifted?Boolean

Returns:

  • (Boolean)


110
111
112
# File 'lib/lambda_driver/liftable.rb', line 110

def lambda_driver_lifted?
  @lambda_driver_lifted
end

#lift(ctx = DEFAULT_CONTEXT, &block) ⇒ Object

Lift this function to the given context-function. The lifted fucntion can compose other function with context-fucntion.

The given context-fuction used by ‘compose_with_lifting` to compose other fucntion.

The context-funciton should recieve 2 arguments.

- first one is a function that reciver function of `compose_with_lifting` method.
- second arg is a result of g(x)
-- g is a function passed to `compose_with_lifting`


92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
# File 'lib/lambda_driver/liftable.rb', line 92

def lift(ctx = DEFAULT_CONTEXT, &block)
  ctx = block_given? ? block : ctx
  ctx = case ctx
    when String, Symbol then LambdaDriver::Context[ctx]
    else ctx
  end

  # do not lift same context again
  return self if lambda_driver_lifted? && (ctx == lambda_driver_liftable_context)

  lambda{|*args| ctx.call(self, *args) }.tap{|f|
    f.instance_eval do
      @lambda_driver_lifted = true
      @lambda_driver_liftable_context = ctx
    end
  }
end