레코드는 함께 묶이는 필드들의 모음이고, 필드는 서로 다른 타입일 수 있어요. 레코드를 정의하려면 type 키워드를 사용해요. 레코드의 필드는 {와 } 문자 사이에 정의하고, 각 필드에는 _이름과 타입_이 있어요. 레코드를 만들려면 {와 } 문자 사이에 필드 이름을 적고 값을 할당해요. 레코드를 만들 때는 모든 필드에 값을 할당해야 해요. 레코드 인스턴스의 필드 값은 점 표기법으로 접근할 수 있어요.
레코드를 정의하거나 만들 때, 각 필드는 한 줄에 하나씩 두거나, 한 줄에 쓸 때는 세미콜론(;)으로 구분해야 해요.
// 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 키워드로 기존 레코드의 복사본을 만들 수 있는데, 하나 이상의 필드에 새로운 값을 지정할 수 있어요.
// Copy the old address but change the house number
let newAddress: Address = { oldAddress with HouseNumber = 86 }
newAddress.Street // => "Main Street"
newAddress.HouseNumber // => 86
레코드는 _구조적 동등성_을 가져요. 즉, 같은 레코드의 두 인스턴스가 동일한 값을 가지면 서로 동등해요.
점 표기법으로 레코드의 필드에 접근할 수 있는 것 외에도, 레코드는 바인딩과 패턴 매칭에서 _분해_할 수 있어요:
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 역사를 깊이 파고들면서 팀과 감독, 승패 기록을 정리하고 서로 비교해요.
아직 좋아하는 팀이 없어서, 특정 팀을 응원할지 판단하는 알고리즘도 만들어 볼 거예요.
자신만의 팀 응원 알고리즘을 개발하는 데 도움이 될 일곱 개의 작업이 있어요.
다음 두 필드를 가진 Coach 레코드를 정의해요:
Name: 감독의 이름, 타입은 string.FormerPlayer: 감독이 선수 출신이었는지 나타내요, 타입은 bool.다음 두 필드를 가진 Stats 레코드를 정의해요:
Wins: 승리 수, 타입은 int.Losses: 패배 수, 타입은 int.다음 세 필드를 가진 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 } }
전적을 파고들다 보면 팀과 그 전적을 목록으로 정리하게 돼요. 가끔 실수해서 목록에 중복된 항목이 생기기도 해요. 두 팀을 받아 같은 팀이면 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를 반환하는 rootForTeam 함수를 구현해요:
let spursCoach = createCoach "Gregg Popovich" false
let spursStats = createStats 56 26
let spursTeam = createTeam "San Antonio Spurs" spursCoach spursStats
rootForTeam spursTeam
// => true
Exercism에 가입하고 F# 트랙을 개념 18개연습 문제 148개, 그리고 실제 사람의 멘토링과 함께 배우고 익혀 보세요. 모두 무료예요.