Home About Contact
Haskell

Haskell / data とそのフィールド値の取得

前回 ポケモン型を使いましたが、そのフィールドを取得する方法を整理します。

Groovy で書くとこんなコード:

enum PokemonType {
     NORMAL,
     WATER,
     ELECTRIC,
     FIRE,
}

class Pokemon {
    String name
    PokemonType type
}

def pokemon1 = new Pokemon("Pikachu", PokemonType.ELECTRIC)
println pokemon1.name
println pokemon1.type

Step1 基本

これを Haskell で書いてみます。

pokmondata.hs:

data PokemonType = Normal | Water | Electric | Fire deriving Show
data Pokemon = Pokemon String, PokemonType deriving Show

toName :: Pokemon -> String
toName (Pokemon n _) = n

toPokemonType :: Pokemon -> PokemonType
toPokemonType (Pokemon _ t) = t

これを GHCi で使ってみましょう:

$ ghci
> :load pokemondata.hs
> pokemon1 = Pokemon "Pikachu" Electric
> pokemon1
Pokemon "Pikachu" Electric
> toName pokemon1
"Pikachu"
> toPokemonType pokemon1
Electric

Step2 レコード構文を使う

data をレコード構文で記述すると、toName や toPokemonType 関数をわざわざ書かなくてもよいとのこと。 それを試します。

data PokemonType = Normal | Water | Electric | Fire deriving Show
data Pokemon = Pokemon { name :: String
                       , pokemonType :: PokemonType } deriving Show

実行する:

> :reload
> pokemon1 = Pokemon "Pikachu" Electric
> name pokemon1
"Pikachu"
> pokemonType pokemon1
Electric

できました。

Step3 フィールドがタプルの場合

もし、前回書いたように Pokemon 型のフィールドをタプルにした場合は:

data PokemonType = Normal | Water | Electric | Fire deriving Show
data Pokemon = Pokemon (String, PokemonType) deriving Show

name :: Pokemon -> String
name (Pokemon v) = fst v

pokemonType :: Pokemon -> PokemonType
pokemonType (Pokemon v) = snd v

関数名を toName, toPokemonType ではなく、先ほどレコード構文で定義した場合と同じにしてみました。

実行する:

> :reload
> pokemon1 = Pokemon "Pikachu" Electric
> name pokemon1
"Pikachu"
> pokemonType pokemon1
Electric

できました。