As John Kelly pointed out to me in another thread, there's a trick called a 
"phantom type" that's possible in Elm. It's where a union type has a type 
variable that's not used on the right side. If you don't expose the 
constructor, you can use the type to only allow values that have come 
through other functions. Here's an example:

-- the Phantom Type
type Measurement a
    = M Float

-- "dummy" types
type Length = Length
type Width = Width
type Area = Area

add : Measurement a -> Measurement a -> Measurement a
add (M a) (M b) =
    M (a + b)

multiply : Measurement Length -> Measurement Width -> Measurement Area
multiply (M a) (M b) =
    M (a * b)


I've been thinking about how to make these guarantees, there was a recent 
ThoughtBots post on it, and I'm not sure anyone has seen this before. 
Building out a whole system of measurement this way seems really tedious, 
but for a smaller and more specific problem, it might be a valuable 
technique to know about.

Note that this only works if it's impossible to create a polymorphic type, 
e.g. *Measurement a*, because that will get unified with whatever type is 
expected by the annotation. If every Measurement value is concrete, it 
can't be passed in the wrong place.

As I've been thinking about this, I've seen multiple orthogonal pieces of 
information that we sometimes sloppily roll up into the type:

   - The *representation*, the storage of bits in memory, such as IEEE 
   floating point or 64-bit integer.
   - The *dimension*, in the physics sense, such as length*mass.
   - The *interpretation*. Is it length or width or height? Is length*mass 
   torque or momentum?
   - The *units*, such as meter*kilograms.

When dealing with a discrete case -- the classic example is not mixing up 
rows and columns in a grid/table -- we need the representation and the 
interpretation (rows or columns), but units and dimensions seem not to 
apply. Similarly, if we want to distinguish between strings (URLs, IDs, 
escaped and unescaped HTML, and so on), we seem to want the same things.

It might be interesting to have a wrapped String library that would perform 
the typical operations on strings with type-level identifiers, so when you 
require an ID (aliased to WrapedString IDType) you can only get one that's 
been through your validator. Or you could build URL-specific abstractions 
like *Url.join : Url -> List String -> Url*.

So, just a neat idea not everyone is aware of, hopefully someone finds it 
interesting or useful.

-- 
You received this message because you are subscribed to the Google Groups "Elm 
Discuss" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to elm-discuss+unsubscr...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Reply via email to