【解答例】Haskell 代数的データ型 超入門

More than 3 years have passed since last update.

Haskell 代数的データ型 超入門の解答例です。


列挙型

【問1】光の三原色と、2つの色を混合する関数mixを定義してください。混ぜることによってできる色も定義の対象とします。ただし同じ成分同士は強め合わないものとします。

条件を列挙します。逆の組み合わせを一括処理しているのがポイントです。

data Color = Blue | Red | Magenta | Green | Cyan | Yellow | White

deriving (Show, Eq)

mix Blue Red = Magenta
mix Blue Magenta = Magenta
mix Blue Green = Cyan
mix Blue Cyan = Cyan
mix Blue Yellow = White
mix Red Magenta = Magenta
mix Red Green = Yellow
mix Red Cyan = White
mix Red Yellow = Yellow
mix Magenta Green = White
mix Magenta Cyan = White
mix Magenta Yellow = White
mix Green Cyan = Cyan
mix Green Yellow = Yellow
mix Cyan Yellow = White
mix White _ = White
mix c1 c2 | c1 == c2 = c1
| otherwise = mix c2 c1

main = do
print $ mix Blue Blue
print $ mix Red Blue
print $ mix Red $ mix Blue Green


実行結果

Blue

Magenta
White


別解

ビット演算で簡単に書けます。

import Data.Bits

data Color = Black | Blue | Red | Magenta | Green | Cyan | Yellow | White
deriving (Show, Enum)

mix c1 c2 = toEnum (fromEnum c1 .|. fromEnum c2) :: Color

main = do
print $ mix Red Blue
print $ mix Red $ mix Blue Green


実行結果

Magenta

White


直積型

【問2】x,y,w,hを表現したRect型を定義して、RectPointが含まれるかどうかを判定する関数containsを実装してください。

data Point = Point Int Int deriving Show

data Rect = Rect Int Int Int Int deriving Show

contains (Rect x y w h) (Point px py) =
x <= px && px < x + w && y <= py && py < y + h

main = do
print $ contains (Rect 2 2 3 3) (Point 1 1)
print $ contains (Rect 2 2 3 3) (Point 2 2)
print $ contains (Rect 2 2 3 3) (Point 3 3)
print $ contains (Rect 2 2 3 3) (Point 4 4)
print $ contains (Rect 2 2 3 3) (Point 5 5)


実行結果

False

True
True
True
False


直和型

【問3】RectPointを2次元と3次元の両方に対応させて、問2のcontainsも対応させてください。

data Point = Point   Int Int

| Point3D Int Int Int
deriving Show

data Rect = Rect Int Int Int Int
| Rect3D Int Int Int Int Int Int
deriving Show

contains (Rect x y w h) (Point px py) =
x <= px && px < x + w && y <= py && py < y + h

contains (Rect3D x y z w h d) (Point3D px py pz) =
x <= px && px < x + w &&
y <= py && py < y + h &&
z <= pz && pz < z + d

main = do
print $ contains (Rect 2 2 3 3) (Point 1 1)
print $ contains (Rect 2 2 3 3) (Point 2 2)
print $ contains (Rect 2 2 3 3) (Point 3 3)
print $ contains (Rect 2 2 3 3) (Point 4 4)
print $ contains (Rect 2 2 3 3) (Point 5 5)
print $ contains (Rect3D 2 2 2 3 3 3) (Point3D 1 1 1)
print $ contains (Rect3D 2 2 2 3 3 3) (Point3D 2 2 2)
print $ contains (Rect3D 2 2 2 3 3 3) (Point3D 3 3 3)
print $ contains (Rect3D 2 2 2 3 3 3) (Point3D 4 4 4)
print $ contains (Rect3D 2 2 2 3 3 3) (Point3D 5 5 5)


実行結果

False

True
True
True
False
False
True
True
True
False


レコード構文

【問4】問2の解答をレコード構文で書き直してください。

data Point = Point { px :: Int, py :: Int } deriving Show

data Rect = Rect { rx :: Int, ry :: Int, rw :: Int, rh :: Int } deriving Show

contains r p =
(rx r) <= (px p) && (px p) < (rx r) + (rw r) &&
(ry r) <= (py p) && (py p) < (ry r) + (rh r)

main = do
print $ contains Rect { rx = 2, ry = 2, rw = 3, rh = 3 } Point { px = 1, py = 1 }
print $ contains Rect { rx = 2, ry = 2, rw = 3, rh = 3 } Point { px = 2, py = 2 }
print $ contains Rect { rx = 2, ry = 2, rw = 3, rh = 3 } Point { px = 3, py = 3 }
print $ contains Rect { rx = 2, ry = 2, rw = 3, rh = 3 } Point { px = 4, py = 4 }
print $ contains Rect { rx = 2, ry = 2, rw = 3, rh = 3 } Point { px = 5, py = 5 }


実行結果

False

True
True
True
False