Extending `Array.of` behaviour to `Set`, `Range` etc

I am in a situation where I have container types other than Array, and want to be able to specify a member type. I’m not sure how, or even if I can just extend the existing code to do this.

Specifically, I’m looking to be able to do things like Set.of(Symbol) or Range.of(Time). Is there any way to do this?

If you’re asking whether dry-types can express this today, not to my knowledge.

Array.of works because Arrays are first-class type objects in the system; Set and Range are not, so while you could define nominal types for them, in order to do member type-checking you would need to implement member classes like Array has.

But types are not that useful on their own, so in order for schemas and contracts to understand these types, you would also need to introduce AST support for them.

In other words: it would be possible to do this, but it’s high-effort.

I mean is it possible to subclass Dry::Types::Array or otherwise refactor it into something more generic (eg a Dry::Types::Container, Dry::Types::Enumerable?) that can represent an arbitrary container-like object that has members that are all of the same type (eg Set, Range…).

I’m using dry-types for validation/coercion on a parameter registry module. One of the things it does is coerce composite types (I am particularly interested in sets and ranges) out of arrays of scalar values which themselves are coerced (into numbers, dates, etc) from strings. The current solution is a bit tortured, because while I could use Array.of if what I actually wanted was an array, I can’t express this kind of thing uniformly for all “container-shaped” objects.