Quick actions

cmd+k|ctrl+k

Navigation

Languages

type check and curry

Snippet info

Language

Ruby

Visibility

public

Author

hyrious

Created

2018-08-27T10:10:50Z

Updated

2018-08-27T11:23:30Z

def mydef(n, **k, &b)
  raise LocalJumpError, 'no block given' unless block_given?
  raise ArgumentError, 'arity not matched' unless b.arity == k.size
  define_singleton_method n do |*xs|
    a, ts = [], k.values
    c = -> x do
      x.is_a?(t = ts.shift)?(a << x):(raise TypeError, "expect #{t}, got #{x}")
      ts.empty? ? b.(*a) : c
    end
    xs.inject(c) { |r, x| r = r.(x) }
  end
end

mydef(:add, a: Integer, b: Integer) { |a, b| a + b }
p add(3, 5)
p add(3).(5)
p add.(3).(5)
# add(0.1, 0.2)

module T
  @@__t = { :' reserved types ' => [] }
  def typed(*ts)
    @@__t[:' reserved types '] = ts
  end
  def method_added(name)
    unless @@__t.include?(name)
      @@__t[name] = @@__t[:' reserved types ']
      return if @@__t[name].empty?
      @@__t[:' reserved types '] = []
      old = instance_method(name)
      define_method name do |*xs|
        a, ts, b = [], @@__t[name].clone, old.bind(self)
        c = -> x do
          if x.is_a?(t = ts.shift)
            a << x
          else
            raise TypeError, "expect #{t}, got #{x.inspect}"
          end
          ts.empty? ? b.(*a) : c
        end
        xs.inject(c) { |r, x| r = r.(x) }
      end
    end
  end
end

class A
  extend T
  def add a, b
    a + b
  end
  typed Integer, Integer
  def mul a, b
    a * b
  end
end

a = A.new
p a.add(3, 5)
p a.add('3', '5')
p a.mul(3, 5)
# a.mul('3', 5)
INFO