関数

【Haskell】関数におけるcase式

【Haskell】関数におけるcase式

Haskellの関数におけるcaseの使い方の基本について解説します。

関数におけるcase式

Haskellは、純粋関数型のプログラミング言語のひとつです。Haskellでのプログラミングでは関数が中心となります。Haskellの関数の基本については「関数の基本」でまとめていますので参考にしてください。

Haskellの関数の実装の際に、条件分岐するために便利な式としてcaseというものがあります。C/C++等の他の言語を知っている人であればswitch caseのような条件分岐の構文が出てきますが概念としては同じようなものです。

ただし、Haskellのcase式はそれよりも強力なものです。C/C++のswitch caseでは、主に整数値や列挙型との一致で分岐させることに限定されていますが、Haskellのcase式では値によって評価して分岐するだけではなく、パターンによってマッチさせることも可能であり、より表現力が高くなります。

本記事では、Haskellの関数におけるcase式の使い方の基本について紹介します。

case式の基本的な使い方

case式の構文

case式の構文は以下のようになります。

case
case expression of
    pattern1 -> result1
    pattern2 -> result2
    ...

構文自体は非常に分かりやすいかと思います。expressionpattern1に該当する場合には、式の評価結果としてはresult1となります。

case式の使用例

case式の簡単な例で使い方を見てみましょう。

data Fruit = Apple | Orange | Banana

fruitColor :: Fruit -> String
fruitColor fruit = case fruit of
    Apple  -> "Red"
    Orange -> "Orange"
    Banana -> "Yellow"
【関数使用結果例】
ghci> fruitColor Apple
"Red"
ghci> fruitColor Orange
"Orange"
ghci> fruitColor Banana
"Yellow"

上記例では、Fruit型という型を定義して、その値としてはApple, Orange, Bananaというものを持っています。fruitColor関数は、Fruit型の引数を受け取り、その色を返却するような関数です。

case式では、関数が引数として受け取ったfruitの値をその後に記載したパターンに合わせて、文字列が変化していることが分かるかと思います。

Haskellのcase式では、パターンにマッチさせることも可能であることに冒頭で少し触れました。少し複雑な例を見てみましょう。

data Shape = Circle Float | Rectangle Float Float

area s = case s of
    (Circle r) -> pi * r * r
    (Rectangle w h) -> w * h
【関数使用結果例】
ghci> area (Circle 5)
78.53982
ghci> area (Rectangle 2 5)
10.0

上記例のShepe型は、 円(Circle)または矩形(Rectangle)を表すようなデータ型になっており、どちらであるかで持っている値の数が異なります。case式のパターンでは、円であれば(Circle r)(Rectangle w h)といったようにパターンによってマッチさせて、値を使った計算式とすることが可能です。

このように、Haskellのcase式では値の一致やパターンマッチにより条件分岐させることが可能です。

関数の引数に対するパターンマッチとcase式の違い

Haskellの関数では、引数に対してパターンマッチさせて実装することが可能です。関数の引数に対するパターンマッチについては「関数におけるパターンマッチ」でまとめていますので参考にしてください。

例えば上記で紹介したarea関数は、関数の引数のパターンマッチとして以下のarea'関数のように書くことも可能です。

data Shape = Circle Float | Rectangle Float Float
 
area' :: Shape -> Float
area' (Circle r) = pi * r * r
area' (Rectangle w h) = w * h

関数の引数のパターンマッチとcase式の違いは、引数に対してパターンを定義するのか、関数内の特定の式に対して行うかという点です。では、どちらを使用するかということになると思いますが、これは解決したい問題によりよく検討する必要があります。

関数のパターンマッチは、引数の型や構造に密接に関連して関数の振る舞いが決まるような場合に特に有用です。汎用的で再利用可能な関数を作成するのに適しています。一方で、case式は特定の関数内でのみ必要な複雑な条件分岐のロジックを実装する場合に適しています。

最終的にどちらの方法を選択するかは、特定の問題の文脈やコードの可読性、保守性などを十分に考慮して決める必要があります。よりシンプルで直感的な方法を選択できると良いでしょう。

まとめ

Haskellの関数におけるcaseの使い方の基本について解説しました。

Haskellのcase式は、C/C++等のswitch caseのような条件分岐に近い概念ですが、より強力なものです。case式では値によって評価して分岐するだけではなく、パターンによってマッチさせることも可能であり、より表現力が高くなります。

本記事では、case式の使い方の基本を例を使って紹介しました。また、関数の引数におけるパターンマッチとの違いや使い分けについても説明しています。

case式は、Haskellの関数定義の表現力を上げるために重要なものになるため、是非使い方を覚えてもらえたらなと思います。