Re: [Haskell-cafe] phantom types and record syntax
Le jeu. 18 juin 2015 à 04:45, Dimitri DeFigueiredo <[hidden email]> a écrit :
I am surprised that this program compiles in GHC:
My trouble is that it seems the record syntax is *implicitly* converting from one
type to the other. It seems I would have to remove the phantom type
by adding a tag to avoid this:
This is faulty reasoning because it imply that a value changed type in your code, based on your understanding that the record syntax is "changing" a value...
This is not the case ! Haskell is functional, immutability is the rule. The record syntax is just a shortcut to create a new value sharing some of its parts with the old value. It is thus perfectly normal that the type of this new value can be different of the type of the old value if no other constraint prevent this (and Phantom types are by essence unconstrained by the value, that is why they're "Phantom").
But this makes me unwilling to use phantom types for security as I
would be worried of unwittingly making the conversion.
The value of Phantom types is generally only displayed if you make them abstract types, since the only way to constrain the phantom type is by imposing restrictive signatures for your handling functions (and then using those restricted functions)... This is why you usually won't export the constructors, only smart constructors that can only produce a precise type of value with the right phantom type. In these conditions, you can't "unwittingly make a conversion" and your API impose a safe pattern of use, helped by the type system to interdict unsafe combination without any runtime cost.
Could somebody sprinkle some insight into why this is "converted
automatically" for phantom types?
Is there another way around this?
As I said, your perspective is wrong : there is no "conversion" here, simply a new value with a new type. I really fail to see why you would want your program to fail to compile, your "sanitize" is exactly the kind of function Phantom types are for : supposing you can only create "Username UserSupplied" with your API, and a part of your API only accept "Username Safe", you'll need a function like sanitize to bridge those two parts.