[Haskell-cafe] Re: Type system speculation

Luke Palmer lrpalmer at gmail.com
Thu Dec 10 18:02:30 EST 2009


On Thu, Dec 10, 2009 at 1:46 PM, Andrew Coppin
<andrewcoppin at btinternet.com> wrote:
> oleg at okmij.org wrote:
>>
>> Andrew Coppin wrote:
>>
>>>
>>> What we're really trying to do here is attach additional information to a
>>> value - information which exists only in the type checker's head, but has
>>> no
>>> effect on runtime behaviour.
>>>
>>
>> Haskell has had the ability to attach arbitrary many pieces of
>> (type-level) data to arbitrary types for a long time -- ever since
>> multi-parameter type classes and functional dependencies have been
>> introduced. Nowadays, type families accomplish the same with fewer
>> keystrokes. One merely needs to define a type family
>>        type family Attrib n index :: *
>> which maps the existing type n and the index to an arbitrary type.
>>
>
> Ah, good point. I hadn't thought of that!
>
> So it seems you can indeed attach arbitrary attributes to any type, any
> time. However, I don't immediately see a way to construct a "safe" string
> type and an "unsafe" string type, so that you can write code which
> distinguishes between them, but that existing code that just expects a plain
> ordinary string still works.

Well, what does existing code which just returns a plain ordinary
string return?  Presumably unsafe, so there would have to be a way to
bias.

> You could newtype string as two new types and
> attach whatever attributes you want to these types, but then normal string
> functions wouldn't work. Any ideas?

That is the way I do it, with explicit conversion functions to
indicate what I think is going on.  As I pointed out, while passing a
specialized version to ordinary functions might work (a common
technique in OO), getting them back is another matter.

module SafeString (String, fromSafe, safe)
import Prelude hiding (String)

newtype String = String { fromSafe :: Prelude.String }

safe :: Prelude.String -> Maybe String
safe s | verify s = Just (String s)
       | otherwise = Nothing

And put in calls to safe and fromSafe explicitly.  You might see this
as a pain, but half of them (the safe calls) are adding value by
forcing you to deal with it if your transformations are not
safety-preserving.  The fromSafe calls could technically be omitted,
though you could argue that they are providing a nice abstraction
barrier too:  SafeStrings, being a subtype, might have a better
representation[1] than ordinary Strings, which you may later decide,
so fromSafe is providing you with the opportunity to change that later
without affecting the client code.

[1] For example (1) a bit-packed representation to save a little
space, or (2) allowing the SafeString module to be reproduced in a
proof assistant where the String type contains proof of its safety, so
that you can verify the client code verbatim  (This is currently not
possible, but it is something I imagine being possible :-).

Luke


More information about the Haskell-Cafe mailing list