mostly-adequate-guide-ko
  • README
  • Chapter 01: 그래서 우린 대체 뭘 할건가요?
    • 소개하기
    • 간단하게 만나보기
  • Chapter 02: 일급 함수 (First Class Functions)
    • 훑어보기
    • 왜 일급을 선호하나요?
  • Chapter 03: 순수 함수를 통해 진정한 행복을 만나보세요
    • 순수해지기
    • Side Effects May Include...
    • 8th Grade Math
    • The Case for Purity
    • In Summary
  • Chapter 04: Currying
    • Can't Live If Livin' Is without You
    • More Than a Pun / Special Sauce
    • In Summary
    • Exercises
  • Chapter 05: Coding by Composing
    • Functional Husbandry
    • Pointfree
    • Debugging
    • Category Theory
    • In Summary
    • Exercises
  • Chapter 06: Example Application
    • Declarative Coding
    • A Flickr of Functional Programming
    • A Principled Refactor
    • In Summary
  • Chapter 07: Hindley-Milner and Me
    • What's Your Type?
    • Tales from the Cryptic
    • Narrowing the Possibility
    • Free as in Theorem
    • Constraints
    • In Summary
  • Chapter 08: Tupperware
    • The Mighty Container
    • My First Functor
    • Schrödinger's Maybe
    • Use Cases
    • Releasing the Value
    • Pure Error Handling
    • Old McDonald Had Effects...
    • Asynchronous Tasks
    • A Spot of Theory
    • In Summary
    • Exercises
  • Chapter 09: Monadic Onions
    • Pointy Functor Factory
    • Mixing Metaphors
    • My Chain Hits My Chest
    • Power Trip
    • Theory
    • In Summary
    • Exercises
  • Chapter 10: Applicative Functors
    • Applying Applicatives
    • Ships in Bottles
    • Coordination Motivation
    • Bro, Do You Even Lift?
    • Operators
    • Free Can Openers
    • Laws
    • In Summary
    • Exercises
  • Chapter 11: Transform Again, Naturally
    • Curse This Nest
    • A Situational Comedy
    • All Natural
    • Principled Type Conversions
    • Feature Envy
    • Isomorphic JavaScript
    • A Broader Definition
    • One Nesting Solution
    • In Summary
    • Exercises
  • Chapter 12: Traversing the Stone
    • Types n' Types
    • Type Feng Shui
    • Effect Assortment
    • Waltz of the Types
    • No Law and Order
    • In Summary
    • Exercises
  • Chapter 13: Monoids bring it all together
    • Wild combination
    • Abstracting addition
    • All my favourite functors are semigroups.
    • Monoids for nothing
    • Folding down the house
    • Not quite a monoid
    • Grand unifying theory
    • Group theory or Category theory?
    • In summary
    • Exercises
  • Appendix A: Essential Functions Support
    • always
    • compose
    • curry
    • either
    • identity
    • inspect
    • left
    • liftA2
    • liftA3
    • maybe
    • nothing
    • reject
  • Appendix B: Algebraic Structures Support
    • Compose
    • Either
    • Identity
    • IO
    • List
    • Map
    • Maybe
    • Task
  • Appendix C: Pointfree Utilities
    • add
    • append
    • chain
    • concat
    • eq
    • filter
    • flip
    • forEach
    • head
    • intercalate
    • join
    • last
    • map
    • match
    • prop
    • reduce
    • replace
    • reverse
    • safeHead
    • safeLast
    • safeProp
    • sequence
    • sortBy
    • split
    • take
    • toLowerCase
    • toString
    • toUpperCase
    • traverse
    • unsafePerformIO
Powered by GitBook
On this page
  • 소개하기
  • 간단하게 만나보기

Chapter 01: 그래서 우린 대체 뭘 할건가요?

소개하기

안녕하세요! 저는 프랭클린 프리스비 교수입니다. 만나서 반갑습니다. 함수형 프로그래밍에 대해 조금 가르쳐 드릴 예정이므로 함께 시간을 보내도록 해보겠습니다. 이제 저에 대해서는 충분한 것 같은데, 당신은 어떤가요? 저는 당신이 최소한 JavaScript 언어에 익숙하고, 약간의 객체 지향 경험이 있고, 스스로 노동계급 프로그래머라고 생각하기를 바랍니다. 곤충학 박사 학위가 없어도 몇몇 버그를 찾아 죽이는 방법만 알면 됩니다.

저는 당신이 함수형 프로그래밍 지식을 가지고 있다고 기대하지 않을 겁니다. 왜냐하면 우리 둘 다 이런 가정을 가졌을 때 어떤 일이 일어나는지 알고 있기 때문입니다. 그러나 아마 당신은 가변 상태, 제한되지 않은 사이드 이펙트 및 원칙 없는 설계를 가지고 작업할 때 불편한 상황을 맞닥드리게 될 겁니다. 이제 제대로 소개했으니 계속 진행해 보겠습니다.

이 장의 목적은 우리가 함수형 프로그램을 작성할 때 무엇을 추구하는지에 대한 느낌을 주는 것입니다. 다음 장을 이해할 수 있으려면 프로그램을 함수형하게 만드는 것에 대한 이해가 있어야 합니다. 그렇지 않으면 우리는 목적 없이 낙서를 하고 온힘을 다해 객체를 피하게 될 것입니다 - 참으로 서투른 노력이 아닐 수 없습니다. 우리는 코드를 던질 수 있는 명확한 과녁이 필요하고 물이 거칠어질 때를 위한 최고의 나침반이 필요합니다.

일반적인 프로그래밍 원칙이 몇 가지 있습니다. 어느 프로그램의 깊은 암흑같은 터널로부터 우리를 빛으로 안내하는 다양한 두문자어 신조들이죠: DRY(반복하지 마세요), YAGNI(필요하지 않을 거에요), 느슨한 결합과 높은 응집력, 놀람 최소화 원칙, 단일 책임 원칙 등.

몇 년 동안 들었던 가이드라인을 일일이 나열해서 당신을 힘들게 하지는 않을게요. 요점은 이 가이드라인들이 비록 우리의 궁극적인 목표와 직접적인 연관은 없지만, 함수적인 사고를 기반으로 설계되어 있다는 점입니다. 더 진도를 나가기 전에 이쯤에서, 여러분이 우리의 함수형 무릉도원을 위해 키보드를 두드리게될 것이란걸 느끼셨으면 좋겠습니다.

간단하게 만나보기

약간의 광기로 시작합시다. 여기 갈매기 프로그램이 있어요. 무리가 결합하면 더 큰 무리가 되고 번식하면 함께 번식하는 갈매기의 수가 증가합니다. 이 코드는 좋은 객체 지향적인 코드를 의도한 것이 아니고, 현대적인 할당 기반 접근법의 위험을 강조하기 위한 것입니다. 보기:

class Flock {
  constructor(n) {
    this.seagulls = n;
  }

  conjoin(other) {
    this.seagulls += other.seagulls;
    return this;
  }

  breed(other) {
    this.seagulls = this.seagulls * other.seagulls;
    return this;
  }
}

const flockA = new Flock(4);
const flockB = new Flock(2);
const flockC = new Flock(0);
const result = flockA
  .conjoin(flockC)
  .breed(flockB)
  .conjoin(flockA.breed(flockB))
  .seagulls;
// 32

도대체 누가 이런 끔찍하고 혐오스러운 것을 만들었을까요? 변화하는 내부 상태를 추적하는 것은 비합리적으로 어렵습니다. 그리고 세상에, 심지어 결과까지 틀렸네요! 16 이어야 했지만, flockA는 작업 도중에 영구적으로 변경되었습니다. 가여운 flockA. 이건 IT의 무정부상태이고! 야생동물 산수입니다!

당신이 이 프로그램을 이해하지 못했다고 할지라도 괜찮습니다. 저도 마찬가지거든요. 여기서 기억해야 할 점은 상태 및 변경 가능한 값은 이러한 작은 예제에서도 따라가기 어렵다는 것입니다.

이번에는 좀 더 함수형 접근방식을 사용하여 다시 시도해보겠습니다:

const conjoin = (flockX, flockY) => flockX + flockY;
const breed = (flockX, flockY) => flockX * flockY;

const flockA = 4;
const flockB = 2;
const flockC = 0;
const result =
    conjoin(breed(flockB, conjoin(flockA, flockC)), breed(flockA, flockB));
// 16

자, 이번에는 우리가 정답을 맞혔습니다. 훨씬 적은 코드로요. 함수 중첩은 약간 혼란스럽네요...(이건 5장에서 개선해 볼게요). 나아지긴 했지만 조금 더 깊이 파헤쳐 보겠습니다. 스페이드를 스페이드라고 부를때 얻을 수 있는 이득이 분명히 있습니다. 사용자 정의 함수를 더 자세히 조사했다면 단순한 덧셈(conjoin)과 곱셈(breed)으로 작업하고 있음을 발견했을 것입니다.

이 두 함수는 이름말고는 특별할 것이 없습니다. 사용자 정의 함수의 이름을 'multiply' 및 'add'로 변경하여 그들의 실체를 드러내 보겠습니다.

const add = (x, y) => x + y;
const multiply = (x, y) => x * y;

const flockA = 4;
const flockB = 2;
const flockC = 0;
const result =
    add(multiply(flockB, add(flockA, flockC)), multiply(flockA, flockB));
// 16

이렇게 함으로서 우리는 진리를 깨우칩니다:

// 결합법칙 (associative)
add(add(x, y), z) === add(x, add(y, z));

// 교환법칙 (commutative)
add(x, y) === add(y, x);

// 항등원 (identity)
add(x, 0) === x;

// 분배법칙 (distributive)
multiply(x, add(y,z)) === add(multiply(x, y), multiply(x, z));

네, 이 오래되고 충실한 수학적 속성들이 유용하게 쓰일겁니다. 당신의 머리에서 이것들을 완전히 이해하지 못해도 걱정하지 마세요. 우리 대부분은 이러한 산술 법칙에 대해 배운지 꽤 오랜 시간이 지났으니까요. 이제 우리의 작은 갈매기 프로그램을 단순화하기 위해 저 속성들을 사용할 수 있을지 봅시다.

// 원래 라인
add(multiply(flockB, add(flockA, flockC)), multiply(flockA, flockB));

// 항등원을 적용하여 불필요한 'add' 제거
// (add(flockA, flockC) == flockA)
add(multiply(flockB, flockA), multiply(flockA, flockB));

// 분배법칙 적용
multiply(flockB, add(flockA, flockA));

굉장합니다! 우리는 조금의 커스텀 코드도 작성하지 않고 해냈어요. 우리는 완전성을 위해서 여기에 add와 multiply 함수 정의를 하기는 했지만 사실 이것도 굳이 할 필요는 없었어요 - 분명 기존 라이브러리 어딘가에서 제공하고 있었을 겁니다.

당신은 아마 "아니 얼마나 한심하면 이런 수학적인 예제를 들이밀까" 또는 "진짜 프로그램은 이렇게 단순하지 않고 이런 식으로 추론할 수 없어"라고 생각할지도 모릅니다. 제가 이 예제를 선택한 이유는 우리가 이미 덧셈과 곳셈을 알고 있고, 그렇기 때문에 수학이 얼마나 우리에게 유용한지를 보여주기 쉬웠기 때문입니다.

체념하지 마세요 - 이 책 전체에 걸쳐 우리는 몇 가지 범주론, 집합론, 람다 미적분과 다양한 'real world' 예제들도 갈매기떼 예제와 같이 우아하게 단순화시키는 경험을 하게 될 겁니다. 수학자가 될 필요는 전혀 없습니다. '일반적인' 프레임워크나 API를 사용하는 것처럼 자연스럽고 쉽게 느껴질거예요.

우리가 일상적으로 작성하던 프로그램을 위와같이 완전히 함수형으로 작성할 수 있다는 사실이 놀랍게 들릴지도 모릅니다. 속성들이 분명하게 들리는 프로그램. 간결하고 이해하기 쉬운 프로그램. 바퀴를 매번 재발명하지 않아도 되는 프로그램. '규칙없음'은 무뢰한에게는 좋을 수 있겠지만, 적어도 이 책에서만큼은 수학의 법칙에 대해 이해하고 따라주시면 좋겠습니다.

우리는 모든 조각이 얌전히 잘 들어맞는 곳에 이론을 적용하기를 원할겁니다. 그리고 우리는 특정 문제를 일반적이고 구성 가능한 조각들로 나타내고, 그 속성들을 활용해서 이득을 보고 싶을 겁니다. 그러려면 명령형 프로그래밍의 "무엇이든" 접근법 보다는 조금 더 규율이 필요합니다("명령형"의 정확한 정의에 대해서는 책의 나중 부분에서 다루겠습니다. 지금은 그저 함수형 프로그래밍이 아닌 모든 것이라고만 생각해 주세요). 절조있고 수학적인 프레임워크를 통해 성과를 내는 경험은 분명히 당신을 경악시킬 겁니다.

저기 우리의 함수형 북극성이 반짝이는게 보입니다, 하지만 우리의 여정을 시작하기 전에 몇 가지 구체적인 개념 이해하고 넘어갈 필요가 있습니다.

PreviousREADMENextChapter 02: 일급 함수 (First Class Functions)

Last updated 2 years ago

Chapter 02: First Class Functions