<div dir="ltr"><div><div><div><div>Record updates have to be able to change the type of the value in order to work with polymorphic fields. Here's a contrived example:<br><br>data Foo a = Foo { foo :: a }<br><br>reFoo x = x { foo = "blarg" }<br><br></div>By the same logic, the resulting type can change the phantom parameter because the phantom parameter is not constrained at all. You could have the same problem without record syntax:<br><br>unsafeId (Username first last) = Username first last<br><br></div>That looks fine—but completely bypasses the phantom type! (In fact, it could even produce a Username Int or something.)<br><br></div>This is a fundamental limitation of phantom types. Since they're not constrained at all, they're very easy to change. They're useful, but more as a convention and a warning than as an ironclad guarantee.<br><br></div><div>In this specific case, I can think of two reasonable options. One is to make the Username type abstract—don't export the constructor and ensure that the only provided ways to make one are safe. Another is to make a String newtype with a flag, and keep that abstract. Domain-specific types like Username could use this newtype for their fields.<br><br></div><div>newtype Str a = Str String<br><br></div><div>data Username a = Username { first :: Str a, last :: Str a }<br><br></div><div>As long as you have access to a Str constructor, you can make "Safe" instances however you like; however, if you keep the type abstract, it can be safe outside the defining module.<br><br></div><div>There are some other design options, and it's something worth thinking about. But what you've found is a fundamental quality (and limitation) of phantom types and has to be kept in mind as you're working with them.<br></div><div><br></div></div><div class="gmail_extra"><br><div class="gmail_quote">On Wed, Jun 17, 2015 at 7:45 PM, Dimitri DeFigueiredo <span dir="ltr"><<a href="mailto:defigueiredo@ucdavis.edu" target="_blank">defigueiredo@ucdavis.edu</a>></span> wrote:<br><blockquote class="gmail_quote" style="margin:0 0 0 .8ex;border-left:1px #ccc solid;padding-left:1ex">
  
    
  
  <div bgcolor="#FFFFFF" text="#000000">
    Hi All, <br>
    <br>
    My apologies if this is not the right forum, but am not satisfied
    with my current understanding.<br>
    <br>
    I am surprised that this program compiles in GHC: <br>
    <br>
    -----<br>
    data UserSupplied  = UserSupplied -- i.e. unsafe<br>
    data Safe          = Safe<br>
    <br>
    data Username a = Username { first :: String, last :: String}<br>
    <br>
    sanitize :: Username UserSupplied -> Username Safe<br>
    sanitize name = name { first = "John" }<br>
    <br>
    main = putStrLn "Hi!"<br>
    -----<br>
    <br>
    My trouble is that it seems the record syntax is<b><span></span><span></span></b> *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: <br>
    <br>
    -----<br>
    data Username a = Username { first :: String, last :: String, tag ::
    a }<br>
    <br>
    sanitize :: Username UserSupplied -> Username Safe<br>
    sanitize name = name { first = "John" } -- FAIL as expected!! :-)<br>
    -----<br>
    <br>
    But this makes me unwilling to use phantom types for security as I
    would be worried of unwittingly making the conversion.<br>
    <br>
    Could somebody sprinkle some insight into why this is "converted
    automatically" for phantom types?<br>
    Is there another way around this? <br>
    <br>
    <br>
    Thanks! <br><span class="HOEnZb"><font color="#888888">
    <br>
    <br>
    Dimitri <br>
    <br>
    <br>
  </font></span></div>

<br>_______________________________________________<br>
Haskell-Cafe mailing list<br>
<a href="mailto:Haskell-Cafe@haskell.org">Haskell-Cafe@haskell.org</a><br>
<a href="http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe" rel="noreferrer" target="_blank">http://mail.haskell.org/cgi-bin/mailman/listinfo/haskell-cafe</a><br>
<br></blockquote></div><br></div>