Difference between revisions of "型"

From HaskellWiki
Jump to navigation Jump to search
Line 1: Line 1:
  +
Haskellでは '''型''' とはプログラム内で用いるデータを表現するものです。
In Haskell, '''types''' are how you describe the data your program will work with.
 
   
 
[[Category:Language]]
 
[[Category:Language]]
Line 5: Line 5:
 
==データの宣言==
 
==データの宣言==
   
  +
Haskellでは型を<code>data</code>宣言を通じて導入、または宣言します。一般的にデータ宣言はこのように行います。
One introduces, or declares, a type in Haskell via the <code>data</code> statement. In general a data declaration looks like:
 
   
 
data [context =>] type tv1 ... tvi = con1 c1t1 c1c2... c1tn |
 
data [context =>] type tv1 ... tvi = con1 c1t1 c1c2... c1tn |
Line 11: Line 11:
 
[deriving]
 
[deriving]
   
  +
まだHaskellをあまり理解していいない方にはおそらく説明になっていないかもしれません。
which probably explains nothing if you don't already know Haskell!
 
   
  +
上の宣言の本質は、<hask>data</hask>キーワードを使って、付属的なコンテキストを与え、型の名前と多くの[[type variable]]を与えることにあります。
The essence of the above statement is that you use the keyword <hask>data</hask>,
 
  +
その後、多くの[[constructor]]が続きます。これらは[[type variable]]か[[type constant]]のリストになっています。最後に付属的に<code>deriving</code>が続きます。
supply an optional context, give the type name and a variable number of
 
[[type variable]]s. This is then followed by a variable number of [[constructor]]s, each of which has a list of [[type variable]]s or [[type constant]]s. At the end, there is an optional <code>deriving</code>.
 
   
  +
他にも多くの微妙な事柄が必要です。たとえばデータコンストラクタに必要なパラメータは[[eager]]でなければならない、どんな[[Type class|class]]が[[deriving]]の中で許可されているか、コンストラクタ内の[[field]]名の使い方、[[context]]が実際になにをするのかなどです。これらについてはそれぞれの記事を参照してください。
There are a number of other subtleties associated with this, such as requiring
 
parameters to the data constructors to be [[eager]], what [[Type class|class]]es are
 
allowed in the [[deriving]], use of [[field]] names in the constructors
 
and what the [[context]] actually does. Please refer to the specific articles for more on each of those.
 
   
  +
いくつかの例を見てみましょう。Haskellの標準データ型[[Maybe]]は普通このように宣言されています。
Let's look at some examples. The Haskell standard data type [[Maybe]] is typically declared as:
 
 
<haskell>
 
<haskell>
 
data Maybe a = Just a | Nothing
 
data Maybe a = Just a | Nothing
 
</haskell>
 
</haskell>
  +
これは、'''Maybe'''型は''a''で表される1つの型変数を持っていて、'''Just'''と'''Nothing'''という2つの[[constructor]]を持っているということを意味しています。(Haskellでは型名とコンストラクタ名は大文字で始まらなければいけないことに注意してください)
What this means is that the type '''Maybe''' has one type variable, represented by the ''a'' and two [[constructor]]s '''Just''' and '''Nothing'''. (Note that Haskell requires type names and constructor names to begin with an uppercase letter). The '''Just''' constructor takes one parameter, ''a''.
 
  +
'''Just'''コンストラクタは1つのパラメータ"a"をとります。
   
  +
他の例として、二分木 (binary [[Tree]])を考えてみましょう。このように表されます。
As another example, consider binary [[Tree]]s. They could be represented by:
 
 
<haskell>
 
<haskell>
 
data Tree a = Branch (Tree a) (Tree a) | Leaf a
 
data Tree a = Branch (Tree a) (Tree a) | Leaf a
 
</haskell>
 
</haskell>
  +
ここで、'''Tree'''のコンストラクタの1つ'''Branch'''はコンストラクタのパラメータには2つのtreeを取る一方で、'''Leaf'''は型変数"a"だけを取ります。Haskellではこういった再帰型は非常によく使われる[[:Category:Idioms |patterns]]です。
Here, one of the constructors, '''Branch''' of '''Tree''' takes two trees as
 
parameters to the constructor, while '''Leaf''' takes the type variable ''a''. This type of recursion is a very common [[:Category:Idioms |pattern]] in Haskell.
 
   
 
==型と新しい型==
 
==型と新しい型==

Revision as of 14:38, 6 December 2009

Haskellでは とはプログラム内で用いるデータを表現するものです。

データの宣言

Haskellでは型をdata宣言を通じて導入、または宣言します。一般的にデータ宣言はこのように行います。

data [context =>] type tv1 ... tvi = con1  c1t1 c1c2... c1tn |
                      ... | conm cmt1 ... cmtq
                    [deriving]

まだHaskellをあまり理解していいない方にはおそらく説明になっていないかもしれません。

上の宣言の本質は、dataキーワードを使って、付属的なコンテキストを与え、型の名前と多くのtype variableを与えることにあります。 その後、多くのconstructorが続きます。これらはtype variabletype constantのリストになっています。最後に付属的にderivingが続きます。

他にも多くの微妙な事柄が必要です。たとえばデータコンストラクタに必要なパラメータはeagerでなければならない、どんなclassderivingの中で許可されているか、コンストラクタ内のfield名の使い方、contextが実際になにをするのかなどです。これらについてはそれぞれの記事を参照してください。

いくつかの例を見てみましょう。Haskellの標準データ型Maybeは普通このように宣言されています。

 data Maybe a = Just a | Nothing

これは、Maybe型はaで表される1つの型変数を持っていて、JustNothingという2つのconstructorを持っているということを意味しています。(Haskellでは型名とコンストラクタ名は大文字で始まらなければいけないことに注意してください) Justコンストラクタは1つのパラメータ"a"をとります。

他の例として、二分木 (binary Tree)を考えてみましょう。このように表されます。

 data Tree a = Branch (Tree a) (Tree a) | Leaf a

ここで、Treeのコンストラクタの1つBranchはコンストラクタのパラメータには2つのtreeを取る一方で、Leafは型変数"a"だけを取ります。Haskellではこういった再帰型は非常によく使われるpatternsです。

型と新しい型

The other two ways one may introduce types to Haskell programs are via the type and newtype statements.

type introduces a synonym for a type and uses the same data constructors. newtype introduces a renaming of a type and requires you to provide new constructors.

When using a type declaration, the type synonym and its base type are interchangeble almost everywhere (There are some restrictions when dealing with instance declarations). For example, if you had the declaration:

 type Name = String

then any function you had declared that had String in its signature could be used on any element of type Name

However, if one had the declaration:

 
  newtype FirstName = FirstName String

this would no longer be the case. Functions would have to be declared that actually were defined on FirstName. Often, one creates a deconstructor at the same time which helps alleviate this requirement. e.g.:

  unFirstName :: FirstName -> String
  unFirstName (FirstName s) = s

This is often done by the use of fields in the newtype. (Note that many consider the Haskell field implementation sub-optimal, while others use it extensively. See Programming guidelines and Future of Haskell)

簡単な例

Suppose you want to create a program to play bridge. You need something to represent cards. Here is one way to do that.

First, create data types for the suit and card number.

 data Suit = Club | Diamond | Heart | Spade
     deriving (Read, Show, Enum, Eq, Ord)

 data CardValue = Two | Three | Four
     | Five | Six | Seven | Eight | Nine | Ten 
     | Jack | Queen | King | Ace
    deriving (Read,  Show, Enum, Eq, Ord)

Each of these uses a deriving clause to allow us to convert them from / to String and Int, test them for equality and ordering. With types like this, where there are no type variables, equality is based upon which constructor is used and order by the order you wrote them. e.g. Three is less than Queen.

Now we define an actual Card

 
 data Card = Card {value::CardValue, 
                    suit::Suit}
    deriving (Read, Show, Eq)

In this definition, we use fields, which give us ready made functions to access the two parts of a Card. Again, type variables were not used, but the data constructor requires its two parameters to be of specific types, CardValue and Suit.

The deriving clause here only specifies three of our desired Classes, we supply instance declarations for Ord and Enum.

 instance Ord Card where
      compare c1 c2  | (value c1 == (value c2)) = compare (suit c1) (suit c2)
                     | otherwise = compare (value c1) (value c2)

 instance Enum Card where
      toEnum n = Card (toEnum (n `div` 4)) (toEnum (n `mod` 4))
      fromEnum c =  4*(fromEnum (value c)) + (fromEnum (suit c))

Finally, we alias the type Deck to a list of Cards and populate the deck with a list comprehension

 type Deck = [Card]

 deck::Deck
 deck = [Card val su | val <- [Two .. Ace], su <- [Club .. Spade]]

追加してください

Further illustrative examples would be most appreciated.

参考

Read the (wanted) articles about data constructors and classes. As well the Haskell 98 report and your chosen implementation (e.g. GHC/Documentation) have the latest words.

Languages: en