Talk:Haskell/Type declarations
From Wikibooks, the open-content textbooks collection
Contents |
[edit] tuples and types
Up to this point, the reader has encountered tuples and some basic motivation for types. Seems like we need to make the connection between tuples and what we're doing here, something along the lines of "well, you already know how to make your own types; just combine things with lists and tuples; but it's still not very convenient... sometimes you want to name a type; and sometimes you have two things that look like they're the same, but for some reason or another, you want to enforce that they are of different types." We could start off with type synonyms, actually, just make synonyms for tuples... and eventually discover that it's not quite good enough. Then data... and then flip back and point out that synonyms can also be used on data. -- Kowey 03:15, 30 December 2006 (UTC)
- This was the first section that I don't feel very comfortable with. Your comment helped actually. I didn't start to realize the possible usefulness of creating your own Types until I was well into the section. I am also a little confused by constructor functions. I see now how they can be used but I feel like I'm missing the bigger picture or the logic behind some of the syntax.--Jberryman (talk) 02:15, 4 March 2008 (UTC)
[edit] CFG looking types
I was just wondering why this doesn't work:
data BalancedParen = OpenParen CloseParen | OpenParen BalancedParen CloseParen | BalancedParen BalancedParen
it gives:
$ ghci
___ ___ _
/ _ \ /\ /\/ __(_)
/ /_\// /_/ / / | | GHC Interactive, version 6.4.2, for Haskell 98.
/ /_\\/ __ / /___| | http://www.haskell.org/ghc/
\____/\/ /_/\____/|_| Type :? for help.
Loading package base-1.0 ... linking ... done.
Prelude> :l varfun.hs
Compiling Main ( varfun.hs, interpreted )
varfun.hs:1:46:
Multiple declarations of `Main.OpenParen'
Declared at: varfun.hs:1:22
varfun.hs:1:46
Failed, modules loaded: none.
Prelude>
I also tried this text in varfun.hs:
data Palindrome = A Palindrome A | B Palindrome B | A | B | A A | B B
It gave:
$ ghci
___ ___ _
/ _ \ /\ /\/ __(_)
/ /_\// /_/ / / | | GHC Interactive, version 6.4.2, for Haskell 98.
/ /_\\/ __ / /___| | http://www.haskell.org/ghc/
\____/\/ /_/\____/|_| Type :? for help.
Loading package base-1.0 ... linking ... done.
Prelude> :l varfun.hs
Compiling Main ( varfun.hs, interpreted )
varfun.hs:1:60:
Multiple declarations of `Main.A'
Declared at: varfun.hs:1:52
varfun.hs:1:60
varfun.hs:1:60:
Multiple declarations of `Main.A'
Declared at: varfun.hs:1:18
varfun.hs:1:60
varfun.hs:1:66:
Multiple declarations of `Main.B'
Declared at: varfun.hs:1:56
varfun.hs:1:66
varfun.hs:1:66:
Multiple declarations of `Main.B'
Declared at: varfun.hs:1:35
varfun.hs:1:66
Failed, modules loaded: none.
Prelude>
[edit] Answer
Well, one thing is as the compiler complains: you can't have multiple declarations of the same type using the same constructor, so this is bad:
data MyWonderfulType = Bar Int | Bar Char -- bad: too many Bars
Whereas this is ok
data MyWonderfulType = Foo Int | Bar Char
Note incidentally that this too is bad...
data MyNiceType = Foo data MyOtherType = Foo -- too many Foos
The basic intuition for this is that when you say Foo in some piece of code, not the type declaration itself, but simply trying to use Foo, you want the Haskell compiler to know what you're talking about. In the case above, we have an ambiguity... was that a MyNiceType you wanted or a MyOtherType?
The other issue is simply a question of syntax, in that a type declaration looks like this...
data MyType = Constructor TypeArg1 TypeArg2 ... TypeArgN
where TypeArg1..TypeArgN are themselves types. (Incidentally, it's ok if the constructor and the type have the same name)
The implications being that a type like the below...
data Palindrome = A Palindrome A
You've got a constructor A, followed by arguments Palindrome and A. That's all well and good, except that
- It's probably not what you had in mind
- ... The type
Aisn't defined anywhere else in your code
Here's something which would probably work better
data A = A data B = B data Palindrome = P1 A Palindrome A | P2 B Palindrome B | P3 A A
Note how I give a constructor (P1...P3) for each alternative in the CFG, and that each constructor is different (can't have multiple declarations, remember? Now, you might be tempted to do something like this...
-- not going to work data Alphabet = A | B | C data Palindrome = P1 A Palindrome A | P2 B Palindrome B | P3 A A
Because what comes after the constructor has to be a type, whereas, A in this case, is NOT a type (Alphabet is a type, as is Palindrome). You could try something like this:
data Alphabet = A | B | C data Palindrome = P1 Alphabet Palindrome Alphabet | P3 Alphabet Alphabet
But then we'd no longer be dealing with a CFG, would we?
Hope this helps. For more questions, please try the haskell mailing list (or perhaps haskell-cafe), or the #haskell IRC channel on irc.freenode.net -- Kowey 06:57, 15 August 2006 (UTC)
[edit] Error
johnSmith = Birthday {
name = "John Smith",
date = Date 7 3 1986}'
name and date are not in scope here (unless i missed something) -- should they read anniName and anniDate? 82.70.93.66 13:32, 2 September 2006 (UTC)
- Fixed, thanks. -- Kowey 20:33, 2 September 2006 (UTC)
[edit] newtype
data X = Y Char newtype X' = Y' Char
X' has 257 possible values while X has 258.
[edit] showAnniversary
showAnniversary didn't work the way the text is implying it should have (I think). I got the impression it should somehow magically tie in with show, so you could just type show smithWedding. But instead you have to type showAnniversary smithWedding. I find this chapter a tad confusing.... 24.65.49.167 (talk) 04:36, 20 March 2008 (UTC) (aka user:Bawolff)
- Well, you absolutely could. Just add a <haskell>deriving (Show)</haskell> clause to the data declaration, and it'll work like you expect.
- But the problem is, that requires two advanced ideas: typeclasses, and instance derivation. And I'm pretty sure those topics don't get covered for a while yet. Having the reader work through things the hard way serves the useful purpose of demonstrating the drudgery we can automate and abstract away later. --Gwern (contribs)
- As a C/C++ programmer trying to learn elementary Haskell, I have to agree with the original poster. Just because it's too early to teach classes and derivation in general doesn't mean you can't use them in this case to aid this tutorial. K&R doesn't have a problem with showing how to print literal text with printf() even though the concepts of how to really take advantage of or write your own printf()-style function don't come until much later. At the very least, mentioning this issue and giving a pointer toward the later subject that provides the solution would be useful. 24.4.188.251 (talk) 06:50, 9 April 2008 (UTC)