def type(type, name = nil, metadata = nil, &bl)
      return subtype(type(type, name, metadata), bl) if bl
      case type
      when Type
        alias_type(type, name, metadata)
      when Module
        BuiltinType.new(type, name || type.name.to_s, metadata)
      when Hash
        tuple(type, name, metadata)
      when Array
        case type.size
        when 0
          fail!("Array of arity > 0 expected, got `#{type}`")
        when 1
          seq(type.first, name, metadata)
        else
          struct(type, name, metadata)
        end
      when Set
        fail!("Set of arity 1 expected, got `#{type}`") unless type.size==1
        sub = type(type.first)
        if sub.is_a?(TupleType)
          relation(sub.heading, name, metadata)
        else
          set(sub, name, metadata)
        end
      when Range
        clazz = [type.begin, type.end].map(&:class).uniq
        fail!("Unsupported range `#{type}`") unless clazz.size==1
        subtype(clazz.first, type, name, metadata)
      when Regexp
        subtype(String, type, name, metadata)
      else
        fail!("Unable to factor a Finitio::Type from `#{type}`")
      end
    end
def type(type, name = nil, metadata = nil, &bl)
      return subtype(type(type, name, metadata), bl) if bl
      case type
      when Type
        alias_type(type, name, metadata)
      when Module
        BuiltinType.new(type, name || type.name.to_s, metadata)
      when Hash
        tuple(type, name, metadata)
      when Array
        case type.size
        when 0
          fail!("Array of arity > 0 expected, got `#{type}`")
        when 1
          seq(type.first, name, metadata)
        else
          struct(type, name, metadata)
        end
      when Set
        fail!("Set of arity 1 expected, got `#{type}`") unless type.size==1
        sub = type(type.first)
        if sub.is_a?(TupleType)
          relation(sub.heading, name, metadata)
        else
          set(sub, name, metadata)
        end
      when Range
        clazz = [type.begin, type.end].map(&:class).uniq
        fail!("Unsupported range `#{type}`") unless clazz.size==1
        subtype(clazz.first, type, name, metadata)
      when Regexp
        subtype(String, type, name, metadata)
      else
        fail!("Unable to factor a Finitio::Type from `#{type}`")
      end
    end
Factory