"Perhaps you can make a 'test type to turn 'testify into a coercion and an 'external-representation type so that 'write can be implemented in terms of 'pr. Maybe you can even replace the 'cons type with a 'list type to avoid the awkward (coerce "" 'cons) semantics, with (type nil) returning 'list."
Yeah perhaps I've been too conservative in designing wart, and I shouldn't be so afraid of proliferating types. Hmm, perhaps if there was a way to automatically coerce types as needed.. Say I wrote a function that can only handle lists, and pass it a string, the runtime dynamically coerces to string. If there's no coercion to string, it finds a coercion through lists of chars.. Hmm, I wonder if people have tried this sort of dynamic searching for paths through the coercions table. If I could do that I'd be more carefree about spawning new types. Just create a new 'test type, write a coercion to 'fn, and everything from before would continue to work.
You're right of course, and I was wrong: you can't disambiguate the cases just by number of args. And even if you could that is perhaps hacky.
Proliferating types is something I don't blame you for worrying about. Since your extension system is based on one extension per type, introducing a new type means extending all the necessary utilities again. At one point I thought that was fine, that I could just put in macros that performed several extensions at once. Now I prefer a base-extensions-on-support-for-other-extensible-things approach for Penknife, but I haven't had enough time to figure out what the pros and cons are.
I've definitely considered that path-search idea before, and I think at one point I talked about why I don't have much faith in it. The short of it is, if there are multiple coercion paths from one type to another, how do you determine which path to use? Be careful; if there's already A->B->C and I define a new type D with A->D and D->C, then code that expects A->B->C might use A->D->C and break. Technically you could propagate the transitive closure each time a coercion is defined, thereby creating the kind of stabiility needed to solve that, but I don't know if that's intuitive enough. Maybe it is. :)
It's definitely one of the goals of wart to minimize the number of methods you have to give a new type to get all the primitives to work. sort isn't generic because the comparison operators are. I think python's __names__ give us a pretty good approximation of what we need.