class Lalka::Task

TODO: Invalidate resolve and reject at the same time

Public Class Methods

new(&block) click to toggle source
# File lib/lalka.rb, line 32
def initialize(&block)
  @computation = block
end
of(value)
Alias for: resolve
reject(error) click to toggle source
# File lib/lalka.rb, line 17
def reject(error)
  new do |t|
    t.reject(error)
  end
end
resolve(value) click to toggle source
# File lib/lalka.rb, line 11
def resolve(value)
  new do |t|
    t.resolve(value)
  end
end
Also aliased as: of
try(&block) click to toggle source
# File lib/lalka.rb, line 23
def try(&block)
  new do |t|
    t.try(&block)
  end
end

Public Instance Methods

ap(other_task) click to toggle source
# File lib/lalka.rb, line 96
def ap(other_task)
  Task.new do |t|
    mutex = Mutex.new
    completed = false
    either = M.Right([M.None(), M.None()])

    complete_task = lambda do |&block|
      mutex.synchronize do
        return if completed

        either = block.call(either)

        if either.right?
          (e_fn, e_arg) = either.value

          e_fn.bind { |fn| e_arg.fmap(fn) }.fmap do |value|
            t.resolve(value)
            completed = true
          end
        else
          error = either.value
          t.reject(error)
          completed = true
        end
      end
    end

    fork do |this|
      this.on_success do |fn|
        complete_task.call do |either|
          either.bind { |_, e_arg| M.Right([M.Some(fn), e_arg]) }
        end
      end

      this.on_error do |error|
        complete_task.call do |either|
          either.bind { M.Left(error) }
        end
      end
    end

    other_task.fork do |other|
      other.on_success do |arg|
        complete_task.call do |either|
          either.bind { |e_fn, _| M.Right([e_fn, M.Some(arg)]) }
        end
      end

      other.on_error do |error|
        complete_task.call do |either|
          either.bind { M.Left(error) }
        end
      end
    end
  end
end
bind(*args, &block) click to toggle source
# File lib/lalka.rb, line 70
def bind(*args, &block)
  block = function_from_arguments(*args, &block)

  Task.new do |t|
    fork do |this|
      this.on_success do |first_value|
        other_task = block.call(first_value)

        other_task.fork do |other|
          other.on_success do |second_value|
            t.resolve(second_value)
          end

          other.on_error do |error|
            t.reject(error)
          end
        end
      end

      this.on_error do |error|
        t.reject(error)
      end
    end
  end
end
Also aliased as: chain, flat_map
chain(*args, &block)
Alias for: bind
flat_map(*args, &block)
Alias for: bind
fmap(*args, &block)
Alias for: map
fork() { |internal| ... } click to toggle source
# File lib/lalka.rb, line 47
def fork
  internal = InternalAsync.new
  yield internal
  internal.call(&@computation)
  nil
end
fork_wait() click to toggle source
# File lib/lalka.rb, line 36
def fork_wait
  queue = Queue.new
  internal = Internal.new(queue)

  internal.on_success { |v| v }
  internal.on_error { |e| e }

  internal.call(&@computation)
  queue.pop
end
map(*args, &block) click to toggle source
# File lib/lalka.rb, line 54
def map(*args, &block)
  block = function_from_arguments(*args, &block)

  Task.new do |t|
    fork do |this|
      this.on_success do |value|
        t.resolve(block.call(value))
      end

      this.on_error do |error|
        t.reject(error)
      end
    end
  end
end
Also aliased as: fmap

Private Instance Methods

function_from_arguments(*args, &block) click to toggle source
# File lib/lalka.rb, line 159
def function_from_arguments(*args, &block)
  if block_given?
    raise ArgumentError, 'both block and function provided' unless args.empty?
    block
  else
    raise ArgumentError, 'no block or function provided' if args.length != 1
    args[0]
  end
end