Haskellerへの道 #9 - レコード

Last Edited: 6/21/2024

このブログ記事では、Haskellにおいて重要なレコードを用いたデータ型の定義方法について紹介しています。

Haskell & Records

データ型の不便性

前回の記事では、新しくデータ型を定義する方法をみてみました。では、Haskellを使ってWebアプリを作ることを 想像してみましょう。Webアプリでは十中八九ユーザーの名前、年齢、メールアドレスなどのデータを Userのデータ型に保存する必要があるでしょう。前回の定義方法を用いるとUserを次のように定義できます。

data User = User String String Int String String

これはすでに雲行きが怪しくなってきましたが、続けてみましょう。Webアプリではユーザーの様々な情報にアクセス する必要があるでしょう。そのためには、以下のような関数を定義する必要があります。

firstName :: User -> String
firstName (User firstname _ _ _ _) = firstname
 
lastName :: User -> String
lastName (User _ lastname _ _ _) = lastname
 
age :: User -> Int
age (User _ _ age _ _) = age
 
email :: User -> String
email = (User _ _ _ email _) = email
 
phoneNumber :: User -> String
phoneNumber (User _ _ _ _ phonenumber) = phonenumber
 
--- 例
user = User "Micheal" "Jordan" 25 "mjordan@gmail.com" "123-456-789"
firstName user --- "Micheal"
age user --- 25

ユーザーの情報にアクセスするためだけに必要な労力としては大きすぎます。。このような関数をすべてのデータ型で書かなければ いけないのでしょうか?幸い、Haskellはもっと簡単な方法を用意してくれています。

レコード

Haskellにはレコードという概念があり、上のような問題を解決してくれます。では早速レコードを使って、Userを再定義 してみましょう。

data User = User {
  firstName :: String,
  lastName :: String,
  age :: Int,
  email :: String,
  phoneNumber :: String
}

上のようにレコードを使ってデータ型を定義すると、Haskellが自動的に各データを抽出できる関数をセットアップしてくれます。

--- 関数を定義しなくても以下のように要素を抽出できます。
user = User "Micheal" "Jordan" 25 "mjordan@gmail.com" "123-456-789"
firstName user --- "Micheal"
age user --- 25

レコードは複数のコンストラクターに同時に用いることもできます。

data Point = 
  D2 {x::Int, y::Int}
  | D3 {x::Int, y::Int, z::Int}
 
x (D2 1 2) --- 1
x (D3 1 2 3) --- 1
z (D2 1 2) --- Err Undefined
z (D3 1 2 3) --- 3

クイズ

この記事では、学習した内容を確認するためのクイズを設けます。記事のメイン部分を読んだ後に、ぜひ自分で問題を解いてみることを強くお勧めします。各問題をクリックすると答えが表示されます。

リソース