top page > computer > haskell > web_lecture > for_programmer > men_and_items.html
更新日:
文責: 重城良国

人間と商品

はじめに

人間を表す型と商品を表す型をはじめは型シノニムで、続けて代数的データ型で表現してみる。後者のほうがより安全であること示す。

型シノニム

hpt.hs

人間

名前と年齢で人間を表す。型シノニムで

type Human = (String, Int)

とする。

年齢

年齢を教える文字列を作る。

age :: Human -> String
age (n, a) = n ++ " is " ++ show a ++ " years old."

32歳のマスオさんだ。

masuo :: Human
masuo = ("Masuo", 32)

% ghci hpt.hs
*Main> age masuo
"Masuo is 32 years old."

商品

商品名と値段で商品を表す。型シノニムで

type Product = (String, Int)

とする。

値段

値段を教える文字列を作る。

price :: Product -> String
price (n, p) = n ++ " is " ++ show p ++ " yen."

iPhone 6sはだいたい99000円くらいだ。

iPhone6s 価格や料金比較

iphone6s :: Product
iphone6s = ("iPhone 6s", 99000)

*Main> :reload
*Main> price iphone6s
"iPhone 6s is 99000 yen."

人間なのか商品なのか

マスオさんの値段やiPhone 6sの年齢を調べてみよう。

*Main> price masuo
"Masuo is 32 yen."
*Main> age iphone6s
"iPhone 6s is 99000 years old."

マスオさんの値段は32円でiPhone 6sは人類がアフリカを出たころには存在していた。

Wikipedia: 地球史年表(10万年前 〜 1万年前)

代数的データ型

hpd.hs

型シノニムとの違い

型シノニムは型の別名だ。型シノニムHumanとProductはどちらも(String, Int)である。関数ageは人間にだけ使いたいし関数priceは商品にだけ使いたい。「代数的データ型」で別名ではなく新しい型を定義する。

人間

名前(String)と年齢(Int)から成る型Humanを定義する。

data Human = Human String Int

左側のHumanは型の名前であり右側のHumanは値構築子だ。型の名前も値構築子も大文字で始める。これらは別々の名前空間に属するので同じ名前でも良い。識別子を考える手間を減らすために同じHumanにした。それぞれ違う識別子として

data Human = Hito String Int

のようにしても良い。例では前者を利用する。

*Main> :load hpd.hs
*Main> Human "Masuo" 32

<interactive>:X:Y:
No instance for (Show Human) arising from a use of `print'
Possible fix: add an instance declaration for (Show Human)
In a stmt of an interactive GHCi command: print it

怒られた。対話環境で表示するにはderiving Showをつける。

data Human = Human String Int deriving Show

*Main> :reload
*Main> Human "Masuo" 32
Human "Masuo" 32
*Main> :t Human "Masuo" 32
Human "Masuo" 32 :: Human

年齢

年齢を教える関数を定義する。値構築子でパターンマッチする。Maybe型の値をJust xでマッチするのと同じだ。

age :: Human -> String
age (Human n a) = n ++ " is " ++ show a ++ " years old."

マスオさんは32歳だ。

masuo :: Human
masuo = Human "Masuo" 32

*Main> :reload
*Main> age masuo
"Masuo is 32 years old."

商品

同様に

data Product = Product String Int

とできる。対話環境で表示するためにderiving Showをつける。

data Product = Product String Int deriving Show

*Main> :reload
*Main> Product "iPhone 6s" 99000
Product "iPhone 6s" 99000
*Main> :t Product "iPhone 6s" 99000
Product "iPhone 6s" 99000 :: Product

値段

値構築子Productでパターンマッチする。

price :: Product -> String
price (Product n p) = n ++ " is " ++ show p ++ "yen."

iPhone 6sはだいたい99000円だ。

iphone6s :: Product
iphone6s = Product "iPhone 6s" 99000

*Main> :reload
*Main> price iphone6s
"iPhone 6s is 99000 yen."

人間なのか商品なのか

マスオさんの値段やiPhone 6sの年齢を調べる。

*Main> price masuo

<interactive>:X:Y:
Couldn't match expected type `Production' with actual type `Human'
In the first argument of `price', namely `masuo'
In the expression: price masuo
*Main> age iphone6s

<interactive>:X:Y:
Couldn't match expected type `Human' with actual type `Product'
In the first argument of `age', namely `iphone6s'
In the expression: age iphone6s

不適切なデータではエラーとなる。適切に型を定義することでバグを減らせる。

構文

既存の型をいくつかまとめて新しい型が作れる。

data [型名] = [値構築子] [型1] [型2] ...

型名と値構築子は大文字から始まる識別子だ。これらは名前空間が異なるので同じ識別子が使える。

まとめ

ここでの使いかたは実質的にはタプルと同じだ。保存したり引き出したりできる値はたとえばStringやIntだ。タプルとの違いは定義された型が「新しい型」となることだ。その型専用の関数でしか使えない。実質的には同じデータから成る型でも違う型となる。型によってコードの安全性がある程度保証される。

課題

  1. 名前と高さで建物を表現する型を作成せよ

「deriving Show」へもどる 「直交座標と極座標」へ

正当なCSSです! HTML5 Powered with CSS3 / styling, and Semantics