Talk:Haskell/Type declarations

From Wikibooks, the open-content textbooks collection

Jump to: navigation, search

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

  1. It's probably not what you had in mind
  2. ... The type A isn'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)