swift

Data Types and Algebra

j2kb 2024. 1. 21. 01:06
반응형

Swift의 데이터 타입과 대수학(Algebra)의 관계에 대해서 알아보도록 하겠습니다.

데이터 타입과 대수학이 관계가 깊다는 얘기를 우연히 접한적이 있습니다. 데이터 타입은 제가 String, Int, Bool, Long, Short, unsigned Int 등 문자열, 실수 정수 등 여러 종류의 데이터를 나타내기 위한 것이다라는 생각을 바로 할 수 있었는데요

 

대수학은 뭘까요??…. 나무위키에 따르면 초중등교육에서는 미지수에 변수를 대입하는 기술이라고 하는데.... 그 이상의 개념은 저는 잘 모르겠어서 암튼 여기까지 하고 일단 넘어가 보겠습니다.

 

 

구조체와 대수학

 

먼저 아래와 같은 구조체를 정의해보겠습니다.

struct Some<T, U> {
	let first: T
	let second: U
}

위 구조체는 제네릭 타입으로 T, U를 받고 first와 second라는 2개의 필드에 각각 T, U의 타입을 가지고 있습니다.

 

만약 T와 U가 Boolean값이라면 Some이라는 구조체가 가질 수 있는 경우의 수는 총 4가지 입니다.

(true, true), (true, false), (false, true), (false, false)

 

만약 Boolean을 T에 3가지의 경우를 가질 수 있는 열거형을 U타입에 넘기면 어떻게 될까요?

enum SomeEnum {
	case a
	case b
	case c
}

Some<Bool, SomeEnum>(first: true, second: .a)
Some<Bool, SomeEnum>(first: true, second: .b)
Some<Bool, SomeEnum>(first: true, second: .c)
Some<Bool, SomeEnum>(first: false, second: .a)
Some<Bool, SomeEnum>(first: false, second: .b)
Some<Bool, SomeEnum>(first: false, second: .c)

이렇게 총 6가지의 경우가 나옵니다. 2*3이죠

 

만약 U의 위치에 Void를 넣으면 어떻게 될까요?? Void는 경우의 수가 () 한 개뿐이므로

2*1의 2가지 경우가 나오죠.

 

Void는 수학적으로 1을 의미한다고 해석하면 될 것 같기도 합니다?!

 

그렇다면 0은 어떻게 표현할까요??

 

간단합니다. Never라는 키워드를 Result타입의 Failure타입에서 보신적이 있으실 거에요.

Failure타입에 있을 경우 발생하지 않는다는 뜻을 나타내게 되는데요. Never의 실제 구현은 아래와 같습니다.

@frozen enum Never { }

케이스가 없는 열거형이네요.

실제로 아래와 같이 U에 Never를 넘길 경우 아예 구조체 인스턴스를 만들 수 조차 없습니다.

Some<Bool, Never>(first: true, second: ...???)

자 잠깐 정리하면

Bool은 2, Void는 1, Never는 0 이네요.

 

그리고 구조체에서는 T와 U의 경우의 수의 곱만큼 실제 구조체가 가질 수 있는 경우의 수가 존재하게 됩니다.

<Bool, Bool> = 2*2

<Bool, Void> = 2*1

<Void, Void> = 1*1

<Bool, Never> = 2*0

 

 

열거형과 대수학

열거형에서는 어떻게 될까요

enum ExampleEnum<T, U> {
	case a(T)
	case b(U)
}

위와 같은 열거형이 있다고 해봅시다. 그리고 구조체에서와 같이 아래의 총 4개의 열거형을 정의해보겠습니다.

ExampleEnum<Bool, Bool>
ExampleEnum<Bool, Void>
ExampleEnum<Void, Void>
ExampleEnum<Bool, Never>

그러면 열거형이 가질 수 있는 경우의 수는 아래와 같습니다

ExampleEnum<Bool, Bool>.a(true)
ExampleEnum<Bool, Bool>.a(false)
ExampleEnum<Bool, Bool>.b(true)
ExampleEnum<Bool, Bool>.b(false)
// 2+2

ExampleEnum<Bool, Void>.a(true)
ExampleEnum<Bool, Void>.a(false)
ExampleEnum<Bool, Void>.b(())
// 2+1

ExampleEnum<Void, Void>.a(())
ExampleEnum<Void, Void>.b(())
// 1+1

ExampleEnum<Bool, Never>.a(true)
ExampleEnum<Bool, Never>.a(false)
// 2+0

구조체와 다르게 곱연산이 아니라 합연산만큼 경우의 수가 있는 것을 볼 수 있습니다.

 

Optional을 예로 들어보겠습니다.

enum Optional<A> {
	case none
	case some<A>
}

여기서 none은 none(Void)로 볼 수 있을 것 같습니다. Optional.none(())와 Optional.none은 언제나 한가지의 경우만 존재하니까요.

 

그래서 Optional<A>의 경우의 수는 1 + A의 경우의 수만큼 존재할 수 있음을 알 수 있고 이를

Optional<A> = A? = 1 + A = Void + A

이렇게 볼 수 있겠네요

 

이걸 아는게 왜 중요할까요???

결론부터 얘기하면 실제 서비스를 만들기 위해 데이터를 모델링할 때 존재하지 않을 케이스를 만들지 않아서 불필요한 작업을 사전에 방지하는데 도움이 되기 때문입니다.

 

유저 정보를 API호출로 받아오는데 거기에는 이름과 나이 전화번호를 준다고 해봅시다.

또 전화번호는 국가코드와 국가코드 번호 그리고 숫자 번호가 있다고 해봅시다. 그리고 전화번호는 유저가 회원가입 시 입력할 수도 있고 안 할수도 있습니다.

이를 모델링 해보겠습니다.

 

첫 번째 방법

struct UserInfo {
	let name: String
	let age: Int
	let phoneNationalCode: String?
	let phoneNationalCodeNumber: String?
	let phoneNumber: String?
}

두 번째 방법

struct UserInfo {
	let name: String
	let age: Int
	var phoneNumber: PhoneNumber?
}

struct PhoneNumber {
	let nationalCode: String
	let nationalCodeNumber: String
	let number: String
}

제 생각에는 2 번째 방법이 보다 잘 도메인을 잘 표현했다고 생각이 듭니다. 단순히 optional unwrapping의 횟수를 3번에서 1번으로 줄여서가 아니라 개념적으로 동시에 존재해야만 존재할 수 있는 3가지 개념들을 제대로 표현해낸 방법이 2번째이기 때문입니다.

 

 

다른 예를 또 들어보겠습니다.

 

대기열 기능을 만드려고 합니다

대기열에는 다음 3가지 상태가 있습니다.

  • 들어가기 전 ready상태
  • 대기열에 들어가서 기다리는 waiting 상태로 이 때는 내 앞에 남은 사람의 숫자 n을 같이 보내줍니다
  • 들어갈 수 있는 상태 finish

서버측에서 API Response 형상 예시를 보내왔습니다. 아래처럼 말이죠

{
	"status": "ready"
}

{
	"status": "waiting",
	"remaining_count": 6,
}

{
	"status": "finish"
}

어떻게 모델링하면 좋을까요??

 

 

첫 번째 방법

enum WaitingStatus {
	case ready
	case waiting
	case finish
}

struct Wating {
	case status: WaitingStatus
	case remainingCount: Int?
}

두 번째 방법

enum WaitingStatus {
	case ready
	case waiting(Int)
	case finish
}

당연히 2번째 방법이 좋습니다. 첫 번째 방법의 경우는 ready인데 9명이 기다리고 있다라는 상태를 가질 수 있는 가능성을 모델링에서 막아주고 있지 않기 때문입니다.

 

 

오랜만에 하는 포스팅이기 때문에 가벼운 글부터 시작해 보았는데요. 도움이 되셨을 지 모르겠네요ㅎㅎ

 

참고

https://namu.wiki/w/대수학

https://www.pointfree.co/episodes/ep4-algebraic-data-types

반응형