
I'm trying to understand the Haskell type system, because it is portrayed as a rather powerful tool when properly harnessed. There are a few things, however, I could use some clarification on. For starters, I'm a bit confused about the "data" declarations: I understand (correctly, I hope) that the purpose of a "data" declaration is to create a new type. So this makes sense: data KeyValuePair = KeyValuePair String String However, this also compiles: data KeyValuePair a b = KeyValuePair String String As well as does this: data KeyValuePair a b = KeyValuePair String And this: data KeyValuePair a b = KeyValuePair So you can see how I'm getting a bit confused? -- frigidcode.com theologia.indicium.us

On Thu, Jun 2, 2011 at 10:03 PM, Christopher Howard
I'm trying to understand the Haskell type system, because it is portrayed as a rather powerful tool when properly harnessed. There are a few things, however, I could use some clarification on. For starters, I'm a bit confused about the "data" declarations:
I understand (correctly, I hope) that the purpose of a "data" declaration is to create a new type. So this makes sense:
data KeyValuePair = KeyValuePair String String
However, this also compiles:
data KeyValuePair a b = KeyValuePair String String
As well as does this:
data KeyValuePair a b = KeyValuePair String
And this:
data KeyValuePair a b = KeyValuePair
So you can see how I'm getting a bit confused?
Yes, 'data' declarations are for introducing a new type. Keep in mind that the type parameters (here 'a' and 'b') are not fundamental to the process - I can also declare
data MyType = MT Integer String
Maybe I can continue the discussion with a question: * Why should the above examples not compile? Then we can more deeply explore your confusion :-) Antoine
-- frigidcode.com theologia.indicium.us
_______________________________________________ Beginners mailing list Beginners@haskell.org http://www.haskell.org/mailman/listinfo/beginners

data KeyValuePair a b = KeyValuePair String String
'a' and 'b' are called phantom types and they are used to tag a datatype. Rather than explain what that means in some abstract way I'll just show you how I have used them: I had the following simple program that retrieved values from and wrote to a dictionary data structure (like Oxford's or Webster's). Here are the types in Haskell: type Name = String type Definition = String type Dictionary = [(Name,Definition)] The actual contents of the dictionary were stored in a SQLite database so I needed to read them into the "Dictionary" type whenever I started up the program. And I had a number of functions that queried the "Dictionary" that required on a populated dictionary and I wanted to check *at compile time* that they would only be called on a populated dictionary. So I added the following two datatypes: data Populated = Populated data New = New I then changed my "Dictionary" to take an extra argument that is never used just like your "KeyValuePair": type Dictionary a = [(Name,Definition)] Now I could write a function that populated the dictionary: populateFromDatabase :: Dictionary New -> IO (Dictionary Populated) and query functions: getDefinition :: Name -> Dictionary Populated -> Definition Since "populateFromDatabase" is the only function that can create a "Dictionary Populated" the phantom type statically guarantees that "getDefinition" and any other function that expects a full dictionary can never be called before "populateFromDatabase". The Haskell Wiki has a similar example [1] and Richard Jones has a nice article on they are used in Ocaml [2] . hth, -deech [1] http://www.haskell.org/haskellwiki/Phantom_type [2] http://camltastic.blogspot.com/2008/05/phantom-types.html

On 06/02/2011 07:58 PM, aditya siram wrote:
data KeyValuePair a b = KeyValuePair String String
'a' and 'b' are called phantom types and they are used to tag a datatype. Rather than explain what that means in some abstract way I'll just show you how I have used them:
I had the following simple program that retrieved values from and wrote to a dictionary data structure (like Oxford's or Webster's). Here are the types in Haskell: type Name = String type Definition = String type Dictionary = [(Name,Definition)]
The actual contents of the dictionary were stored in a SQLite database so I needed to read them into the "Dictionary" type whenever I started up the program.
And I had a number of functions that queried the "Dictionary" that required on a populated dictionary and I wanted to check *at compile time* that they would only be called on a populated dictionary. So I added the following two datatypes: data Populated = Populated data New = New
I then changed my "Dictionary" to take an extra argument that is never used just like your "KeyValuePair": type Dictionary a = [(Name,Definition)]
Now I could write a function that populated the dictionary: populateFromDatabase :: Dictionary New -> IO (Dictionary Populated)
and query functions: getDefinition :: Name -> Dictionary Populated -> Definition
Since "populateFromDatabase" is the only function that can create a "Dictionary Populated" the phantom type statically guarantees that "getDefinition" and any other function that expects a full dictionary can never be called before "populateFromDatabase".
The Haskell Wiki has a similar example [1] and Richard Jones has a nice article on they are used in Ocaml [2] .
hth, -deech
[1] http://www.haskell.org/haskellwiki/Phantom_type [2] http://camltastic.blogspot.com/2008/05/phantom-types.html
Thank you. The first reference link was especially helpful in explaining phantom types. One more question, out of curiosity: In your above example, you could change data Populated = Populated data New = New to simply data Populated data New correct? You might as well, right, since your constructors take no values, and you are just using them as phantom types? -- frigidcode.com theologia.indicium.us

One more question, out of curiosity: In your above example, you could change
data Populated = Populated data New = New
to simply
data Populated data New
correct? You might as well, right, since your constructors take no values, and you are just using them as phantom types?
Yes I think that's correct. You might also look at GADT's [1] which cover some of the same use-cases. -deech [1] http://www.haskell.org/haskellwiki/GADT

On Fri, Jun 3, 2011 at 09:37, aditya siram
One more question, out of curiosity: In your above example, you could change
data Populated = Populated data New = New
to simply
data Populated data New
correct? You might as well, right, since your constructors take no values, and you are just using them as phantom types?
Yes I think that's correct. You might also look at GADT's [1] which cover some of the same use-cases.
The reason for the former is that the latter is not accepted by Haskell 98, so it's a little less portable.
participants (4)
-
aditya siram
-
Antoine Latter
-
Brandon Allbery
-
Christopher Howard