レコードは、互いに関連するフィールド(それぞれ異なる型でもかまいません)をまとめたものです。レコードを定義するには、typeキーワードを使います。レコードのフィールドは{と}の間に定義し、各フィールドには名前_と_型の両方を指定します。レコードを作成するには、フィールドの名前を指定し、{と}の間に値を代入します。レコードを作成するときは、すべてのフィールドに値を代入しなければなりません。レコードのインスタンスのフィールドの値には、ドット記法でアクセスできます。
レコードを定義・作成するときは、各フィールドを別々の行に書くか、1行にまとめる場合はセミコロン(;)で区切ります。
// Define a record
type Address =
{ Street: string
HouseNumber: int }
// Create a record
let oldAddress: Address =
{ Street = "Main Street"
HouseNumber = 17 }
// Single-line alternative
type ConciseAddress = { Street: string; HouseNumber: int }
let conciseAddress: ConciseAddress = { Street = "Main Street"; HouseNumber = 17 }
レコードは不変なので、一度作成したレコードのフィールドの値を後から変更することはできません。レコードの値を変更したい場合は、withキーワードを使うと、既存のレコードのコピーを、1つ以上のフィールドに新しい値を設定した状態で作成できます。
// Copy the old address but change the house number
let newAddress: Address = { oldAddress with HouseNumber = 86 }
newAddress.Street // => "Main Street"
newAddress.HouseNumber // => 86
レコードには_構造的等価性_があります。つまり、同じレコードの2つのインスタンスは、値がまったく同じであれば等しいとみなされます。
ドット記法でレコードのフィールドにアクセスできるだけでなく、レコードは束縛やパターンマッチングの中で_分解_することもできます。
let myAddress: Address = { Street = "Broadway"; HouseNumber = 123 }
let { Street = myStreet; HouseNumber = myHouseNumber } = myAddress
match myAddress with
| { HouseNumber = 1 } -> printfn "First house"
| { HouseNumber = houseNumber; Street = street } -> printfn "House number %d on %s" houseNumber street
// => "House number 123 on Broadway
この演習では、熱心なスポーツファンとしてNBAバスケットボールにハマり始めたばかりです。NBAバスケットボールは初心者なので、NBAの歴史を深く掘り下げ、チームやコーチ、その勝敗成績を記録して、互いに比較していきます。
まだ好きなチームがないので、特定のチームを応援すべきかどうかを判断するアルゴリズムも開発します。
独自の_チームを応援するかどうかを判断する_アルゴリズムを開発するために、7つのタスクがあります。
次の2つのフィールドを持つCoachレコードを定義します。
Name:コーチの名前(型はstringです)。FormerPlayer:コーチが元選手だったかどうかを示します(型はboolです)。次の2つのフィールドを持つStatsレコードを定義します。
Wins:勝ち数(型はintです)。Losses:負け数(型はintです)。次の3つのフィールドを持つTeamレコードを定義します。
Name:チームの名前(型はstringです)。Coach:チームのコーチ(型はCoachです)。Stats:チームの成績(型はStatsです)。コーチの名前と元選手かどうかを入力として受け取り、Coachレコードを返すcreateCoach関数を実装します。
createCoach "Larry Bird" true
// => { Name = "Larry Bird"; FormerPlayer = true }
勝ち数と負け数を入力として受け取り、Statsレコードを返すcreateStats関数を実装します。
createStats 58 24
// => { Wins = 58; Losses = 24 }
チーム名、コーチ、成績のレコードを入力として受け取り、Teamレコードを返すcreateTeam関数を実装します。
let coach = createCoach "Larry Bird" true
let record = createStats 58 24
createTeam "Indiana Pacers" coach record
// => { Name = "Indiana Pacers"
// Coach = { Name = "Larry Bird"; FormerPlayer = true }
// Stats = { Wins = 58; Losses = 24 } }
NBAのオーナーはせっかちなので、チームの成績が悪いとコーチが交代させられることがよくあると気づきました。チームと新しいコーチを入力として受け取り、新しいコーチに差し替えたチームを返すreplaceCoach関数を実装します。
let coach = createCoach "Larry Bird" true
let record = createStats 58 24
let team = createTeam "Indiana Pacers" coach record
let newCoach = createCoach "Isiah Thomas" true
replaceCoach team newCoach
// => { Name = "Indiana Pacers"
// Coach = { Name = "Isiah Thomas"; FormerPlayer = true }
// Stats = { Wins = 58; Losses = 24 } }
成績を調べているうちに、チームとその成績のリストを作っています。ときどき間違えて、リストに重複した項目が入ってしまうことがあります。2つのチームを受け取り、同じチームならtrueを、そうでなければfalseを返すisSameTeam関数を実装します。
let pacersCoach = createCoach "Larry Bird" true
let pacersStats = createStats 58 24
let pacersTeam = createTeam "Indiana Pacers" pacersCoach pacersStats
let lakersCoach = createCoach "Del Harris" false
let lakersStats = createStats 61 21
let lakersTeam = createTeam "LA Lakers" lakersCoach lakersStats
isSameTeam pacersTeam lakersTeam
// => false
多くのチームと試合を見てきた結果、あるアルゴリズムを思いつきました。次のいずれかに当てはまるなら、そのチームを応援します。
チームを受け取り、そのチームを応援すべきならtrueを、そうでなければreturnでfalseを返すrootForTeam関数を実装します。
let spursCoach = createCoach "Gregg Popovich" false
let spursStats = createStats 56 26
let spursTeam = createTeam "San Antonio Spurs" spursCoach spursStats
rootForTeam spursTeam
// => true