Here's a conversation from the FP slack that I'm copy-pasting here for anyone who comes along wondering the same thing as me.
ursi [on Zulip]:zulip: Yesterday at 5:03 PM
I just found
https://pursuit.purescript.org/packages/purescript-coercible/3.0.0
and I noticed it hasn't been touched for 3 years. There's a PR to update it to 0.12, and of course it's not in the package set. This seems like something that would be really nice to have so I found this very surprising. Is there a particular reason why people aren't using it? is it bad practice or something?
natefaubion 21 hours ago
0.14 is getting compiler support for Coercible
natefaubion 21 hours ago
https://github.com/purescript/purescript-safe-coerce
ursi [on Zulip]:zulip: 21 hours ago
by that do you mean there's gonna be a blessed Coericble class that gets optimized away?
natefaubion 21 hours ago
There will be a blessed Coercible that does not require runtime work.
natefaubion 21 hours ago
It will allow you to coerce between types that are representationally equal.
Kim 21 hours ago
But not into a newtype, right?
natefaubion 21 hours ago
If the newtype constructor is exported, you can coerce between a newtype and it’s underlying type.
ursi [on Zulip]:zulip: 21 hours ago
yes, I see, so it's different than the packages I linked, so I guess my question still stands
ursi [on Zulip]:zulip: 21 hours ago
that package has stuff like String -> Array Char
Kim 21 hours ago
Hm, I guess that's practical, but isn't a use of newtypes to keep arguments of the same type apart?
natefaubion 21 hours ago
I think you probably would want something like Rusts Into
natefaubion 21 hours ago
or From
Kim 21 hours ago
Yeah, those are nice
natefaubion 21 hours ago
I don’t think a general Coercible multi-parameter typeclass to convert between arbitrary types is a great idea. It’s difficult to use in practice, and doesn’t end up being different than just calling monomorphic conversion functions.
ursi [on Zulip]:zulip: 21 hours ago
what are the difficulties? I would think it'd be easier :thinking_face: you don't have to remember all the different names of the functions that convert a to b, you just remember one name - coerce
natefaubion 21 hours ago
Because it’s purely type directed
ursi [on Zulip]:zulip: 21 hours ago
I'm sorry, I don't know what you mean by that.
natefaubion 21 hours ago
Decent thread https://twitter.com/taylorfausak/status/1327260662108741633
Taylor FausakTaylor Fausak @taylorfausak
Is a Haskell type class like this a good idea?
class From s t where from :: s -> t
Some example instances are:
instance From a a where from = id
instance From Float Double where from = realToFrac
instance From String Text where from = pack
TwitterTwitter | Nov 13th
natefaubion 21 hours ago
by type directed, I mean the only thing resolving the behavior of the function is the types, which are usually inferred.
natefaubion 21 hours ago
particularly https://twitter.com/kmett/status/1327394471625981952
Edward KmettEdward Kmett @kmett
@taylorfausak No. Instances will overlap like mad. You can write down a bunch, but when you go to use them it goes to hell.
-- act mempty = id
-- act (mappend m n) = act m . act n
class Monoid m => MonoidAction m s where
act :: m -> s -> s
is the example I always want and then recoil from.
TwitterTwitter | Nov 13th
natefaubion 21 hours ago
Actual functions are always more flexible than overloaded constraints, since you don’t have issues with orphans.
natefaubion 21 hours ago
Since this is basically arbitrary conversions, you end up with “what sort of conversions do I want to support in my library”, since they can really only be added to your module where the type is defined (since it likely won’t be with the definition of the class).
ursi [on Zulip]:zulip: 21 hours ago
Since this is basically arbitrary conversions, you end up with “what sort of conversions do I want to support in my library”, since they can really only be added to your module where the type is defined (since it likely won’t be with the definition of the class).
doesn't defining separate functions suffer the same fate? there's conversion functions defined in the library, the others you have to write yourself. You wouldn't be able to write coerce instances yourself if they were missing, but you could still write normal functions, which is the same as not having a coerce (edited)
natefaubion 21 hours ago
Sure, but there’s no community pressure to support this conversion or that for the sake of overloaded convenience.
natefaubion 21 hours ago
One potential solution would just be type directed overloading as mentioned in that thread. That is, no instances. But you can have any number of implementations of the same name, and all that matters is the types involved. They can be defined anywhere, but inference is potentially poor (requiring type signatures to resolve it).
natefaubion 21 hours ago
With type holes, it’s easy to find simple coversions.
natefaubion 21 hours ago
Lots of libraries implement fromFoldable and toUnfoldable, and I frequently have trouble with them, FWIW
ursi [on Zulip]:zulip: 21 hours ago
oh? like what?
natefaubion 21 hours ago
not exactly the same, but considering coerce would be even more arbitrary, I’m not convinced the situation would be better.
natefaubion 21 hours ago
needing type signatures in odd places (edited)
ursi [on Zulip]:zulip: 21 hours ago
hm, I know what you mean - I just did that today - I guess it just doesn't bother me to much cuz it doesn't happen that often and the compiler tells you when it's needed
natefaubion 21 hours ago
I personally put it in the same bucket as a Default class
natefaubion 20 hours ago
that is, there’s no real semantic meaning to it (no laws), it’s just an overloaded convenience. (edited)
ursi [on Zulip]:zulip: 20 hours ago
but isn't the problem with Default that you just can't pick a reasonable default for all conceivable situations? (edited)
ursi [on Zulip]:zulip: 20 hours ago
I feel like with coercible, as long as you stuck to isomorphisms (you could even call it Isomorphism or something) there would generally be only one sensible answer
ursi [on Zulip]:zulip: 20 hours ago
although I'm sure someone can make me eat my words (edited)
natefaubion 20 hours ago
Yeah, I dunno. Generally with stuff like that, the reason it doesn’t exist is likely not because no one thought of it yet 😄
natefaubion 20 hours ago
For PureScript and Haskell in particular, the prevailing attitude is that type classes purely for convenience (as a library) are an anti-pattern.
ursi [on Zulip]:zulip: 20 hours ago
Yeah, I dunno. Generally with stuff like that, the reason it doesn’t exist is likely not because no one thought of it yet 😄
yes sadly this seems to often be the case :p
thanks for the info
ursi [on Zulip]:zulip: 20 hours ago
speak of the devil - @Thimoteus, do you have anything to add to this conversation?
thimoteus:turnstile: 20 hours ago
i found it hard to work with because i needed to add a lot of type signatures, and at the outset it was a way for me to familiarize myself with MPTCs
Here's a conversation from the FP slack that I'm copy-pasting here for anyone who comes along wondering the same thing as me.
ursi [on Zulip]:zulip: Yesterday at 5:03 PM
I just found
https://pursuit.purescript.org/packages/purescript-coercible/3.0.0
and I noticed it hasn't been touched for 3 years. There's a PR to update it to 0.12, and of course it's not in the package set. This seems like something that would be really nice to have so I found this very surprising. Is there a particular reason why people aren't using it? is it bad practice or something?
natefaubion 21 hours ago
0.14 is getting compiler support for Coercible
natefaubion 21 hours ago
https://github.com/purescript/purescript-safe-coerce
ursi [on Zulip]:zulip: 21 hours ago
by that do you mean there's gonna be a blessed Coericble class that gets optimized away?
natefaubion 21 hours ago
There will be a blessed Coercible that does not require runtime work.
natefaubion 21 hours ago
It will allow you to coerce between types that are representationally equal.
Kim 21 hours ago
But not into a newtype, right?
natefaubion 21 hours ago
If the newtype constructor is exported, you can coerce between a newtype and it’s underlying type.
ursi [on Zulip]:zulip: 21 hours ago
yes, I see, so it's different than the packages I linked, so I guess my question still stands
ursi [on Zulip]:zulip: 21 hours ago
that package has stuff like String -> Array Char
Kim 21 hours ago
Hm, I guess that's practical, but isn't a use of newtypes to keep arguments of the same type apart?
natefaubion 21 hours ago
I think you probably would want something like Rusts Into
natefaubion 21 hours ago
or From
Kim 21 hours ago
Yeah, those are nice
natefaubion 21 hours ago
I don’t think a general Coercible multi-parameter typeclass to convert between arbitrary types is a great idea. It’s difficult to use in practice, and doesn’t end up being different than just calling monomorphic conversion functions.
ursi [on Zulip]:zulip: 21 hours ago
what are the difficulties? I would think it'd be easier :thinking_face: you don't have to remember all the different names of the functions that convert a to b, you just remember one name - coerce
natefaubion 21 hours ago
Because it’s purely type directed
ursi [on Zulip]:zulip: 21 hours ago
I'm sorry, I don't know what you mean by that.
natefaubion 21 hours ago
Decent thread https://twitter.com/taylorfausak/status/1327260662108741633
Taylor FausakTaylor Fausak @taylorfausak
Is a Haskell type class like this a good idea?
class From s t where from :: s -> t
Some example instances are:
instance From a a where from = id
instance From Float Double where from = realToFrac
instance From String Text where from = pack
TwitterTwitter | Nov 13th
natefaubion 21 hours ago
by type directed, I mean the only thing resolving the behavior of the function is the types, which are usually inferred.
natefaubion 21 hours ago
particularly https://twitter.com/kmett/status/1327394471625981952
Edward KmettEdward Kmett @kmett
@taylorfausak No. Instances will overlap like mad. You can write down a bunch, but when you go to use them it goes to hell.
-- act mempty = id
-- act (mappend m n) = act m . act n
class Monoid m => MonoidAction m s where
act :: m -> s -> s
is the example I always want and then recoil from.
TwitterTwitter | Nov 13th
natefaubion 21 hours ago
Actual functions are always more flexible than overloaded constraints, since you don’t have issues with orphans.
natefaubion 21 hours ago
Since this is basically arbitrary conversions, you end up with “what sort of conversions do I want to support in my library”, since they can really only be added to your module where the type is defined (since it likely won’t be with the definition of the class).
ursi [on Zulip]:zulip: 21 hours ago
Since this is basically arbitrary conversions, you end up with “what sort of conversions do I want to support in my library”, since they can really only be added to your module where the type is defined (since it likely won’t be with the definition of the class).
doesn't defining separate functions suffer the same fate? there's conversion functions defined in the library, the others you have to write yourself. You wouldn't be able to write coerce instances yourself if they were missing, but you could still write normal functions, which is the same as not having a coerce (edited)
natefaubion 21 hours ago
Sure, but there’s no community pressure to support this conversion or that for the sake of overloaded convenience.
natefaubion 21 hours ago
One potential solution would just be type directed overloading as mentioned in that thread. That is, no instances. But you can have any number of implementations of the same name, and all that matters is the types involved. They can be defined anywhere, but inference is potentially poor (requiring type signatures to resolve it).
natefaubion 21 hours ago
With type holes, it’s easy to find simple coversions.
natefaubion 21 hours ago
Lots of libraries implement fromFoldable and toUnfoldable, and I frequently have trouble with them, FWIW
ursi [on Zulip]:zulip: 21 hours ago
oh? like what?
natefaubion 21 hours ago
not exactly the same, but considering coerce would be even more arbitrary, I’m not convinced the situation would be better.
natefaubion 21 hours ago
needing type signatures in odd places (edited)
ursi [on Zulip]:zulip: 21 hours ago
hm, I know what you mean - I just did that today - I guess it just doesn't bother me to much cuz it doesn't happen that often and the compiler tells you when it's needed
natefaubion 21 hours ago
I personally put it in the same bucket as a Default class
natefaubion 20 hours ago
that is, there’s no real semantic meaning to it (no laws), it’s just an overloaded convenience. (edited)
ursi [on Zulip]:zulip: 20 hours ago
but isn't the problem with Default that you just can't pick a reasonable default for all conceivable situations? (edited)
ursi [on Zulip]:zulip: 20 hours ago
I feel like with coercible, as long as you stuck to isomorphisms (you could even call it Isomorphism or something) there would generally be only one sensible answer
ursi [on Zulip]:zulip: 20 hours ago
although I'm sure someone can make me eat my words (edited)
natefaubion 20 hours ago
Yeah, I dunno. Generally with stuff like that, the reason it doesn’t exist is likely not because no one thought of it yet 😄
natefaubion 20 hours ago
For PureScript and Haskell in particular, the prevailing attitude is that type classes purely for convenience (as a library) are an anti-pattern.
ursi [on Zulip]:zulip: 20 hours ago
Yeah, I dunno. Generally with stuff like that, the reason it doesn’t exist is likely not because no one thought of it yet 😄
yes sadly this seems to often be the case :p
thanks for the info
ursi [on Zulip]:zulip: 20 hours ago
speak of the devil - @Thimoteus, do you have anything to add to this conversation?
thimoteus:turnstile: 20 hours ago
i found it hard to work with because i needed to add a lot of type signatures, and at the outset it was a way for me to familiarize myself with MPTCs