LoginSignup
3

More than 5 years have passed since last update.

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

Last updated at Posted at 2014-09-19

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

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3