A function with type variable Coercible to one of 2 types

Hi,

I figured out that a function working with Strings might be generalized to support all newtypes wrapping a String as follows:

toString :: String -> String
toString :: forall a. Show a => Coercible a String => a -> String 

My question is how to make the function to work with 2 types?

toString :: forall a. Show a => Coercible a String  || Coercible a Int  => a -> String 

Looks like a case for closed type family, but PureScript doesn’t have one.

Instance chain feature helps but causes duplication.

Solution with a dedicated class implemented just by 2 types is not working in PureScript if I talk about predefined types such as String/Int.

P.S.
I have JSON function from a library. Its output format depends on key type. For numbers and strings JSON dictionary is used, meanwhile for other types JSON list.

Edit: Ignore this comment. As @rhendric correctly pointed out, it doesn’t make any sense. I think I was in the mindset of Rust’s into traight, which isn’t even isomorphic let alone coercible.

I’ll leave this here so as to not xonfuse future readers, nit you should ognore it.


What about

=> Coercible a (Either String Int)

?

It can probably extend the other two Coeribles since it’s trivial to prove that

Coercible a String implies Coercible a (Either String Int)

1 Like

@Daniil, there’s no boilerplate-free way to express that a variable type is coercible either to an Int or to a String. The compiler doesn’t backtrack on constraints, so there is no construct you could come up with that would try first one and then the other.

What you could do is create a class and define an instance of that class by hand for every newtype that you work with, with each instance selecting one or the other Coercible relation. They wouldn’t need to be all in a chain, but you would still need to write each one out and your general function wouldn’t work on anything that doesn’t have an instance of this new class. This probably won’t make you happy so I’m refraining from writing out a whole example in advance, but if you’re interested in that sort of solution anyway let me know. (Or you could read this comment and get a pretty good idea of what I’d be selling you.)

The claim made by @Trequetrum is incorrect. Not only does one not imply the other, but it’s impossible to have both Coercible a String and Coercible a (Either String Int) for the same a. Remember that Coercible is an equivalence relation—it is reflexive, symmetric, and transitive—so making this claim is asserting that String and Either String Int have the same run-time representation. They aren’t even isomorphic; how could they have the same run-time representation?

1 Like