Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

02 OOP와 FP #3

Draft
wants to merge 2 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions _includes/sidebar/article-menu.html
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@
function generateContent() {
var menu = document.querySelector(".post-menu");
var menuContent = menu.querySelector(".post-menu-content");
var headings = document.querySelector(".post-content").querySelectorAll("h2, h3, h4, h5, h6");
var headings = document.querySelector(".post-content").querySelectorAll("h1, h2, h3, h4, h5, h6");

// Hide menu when no headings
if (headings.length === 0) {
Expand Down Expand Up @@ -53,16 +53,16 @@
var beginIndex = index;
var endIndex = index + 1;
while (beginIndex >= 0
&& !items[beginIndex].classList.contains('h-h2')) {
&& !items[beginIndex].classList.contains('h-h1')) {
beginIndex -= 1;
}
while (endIndex < items.length
&& !items[endIndex].classList.contains('h-h2')) {
&& !items[endIndex].classList.contains('h-h1')) {
endIndex += 1;
}
for (var i = 0; i < beginIndex; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
if (!item.classList.contains('h-h1')) {
item.style.display = 'none';
}
}
Expand All @@ -74,7 +74,7 @@
}
for (var i = endIndex; i < items.length; i++) {
item = items[i]
if (!item.classList.contains('h-h2')) {
if (!item.classList.contains('h-h1')) {
item.style.display = 'none';
}
}
Expand Down
620 changes: 620 additions & 0 deletions _posts/2022-03-17-TWL-02-1-OOP.md

Large diffs are not rendered by default.

243 changes: 243 additions & 0 deletions _posts/2022-03-17-TWL-02-2-FP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,243 @@
---
layout: post
title: TWL-02 두번째. 함수지향 프로그래밍
subtitle: 함수지향 프로그래밍에 대해 알아봅니다.
categories: [TWL, CS]
tags: [TWL, CS, FP]
---

프로그래밍을 하다보면 간혹 내가 예상한 값과 전혀 다른 결과가 나오곤 합니다. 왜 그런걸까요?
당연하게도 컴퓨터는 거짓말을 하지 않으니 제가 코드를 잘못 짠 탓일겁니다.

개발 도중에 발생하는 문제는 실행시킨 후 얼마 안된 상태를 저장하고 있기 때문에 해결하기가 쉽습니다.
개발 도중에 발생한 문제는 프로그램을 재실행했을 때 금방 같은 문제가 재현되어 원인을 파악하기 쉽기 때문입니다.

<center>
<img src="/assets/2022-03-17-TWL-02-2-FP/01-duggubi.gif" width="250" alt="두꺼비" />
</center>

원인을 제거하지 않으면 결국 뚫립니다.
{: style="text-align: center; color: gray; margin-top:.5em;"}

하지만 한참을 돌던 프로그램이 갑자기 문제가 발생하면 원인 파악이 어렵습니다.
문제의 원인이 되는 코드를 찾지 못해 일단 프로그램에서 에러가 발생하지 않도록 땜빵 코드만 작성하기도 합니다.
하지만 땜빵한 코드는 결국 다른 곳에서 다시 에러를 발생시키기 때문에 임기응변에 그치는 경우가 많습니다.
> 2,3일동안 켜져있던 브라우저가 갑자기 종료되면 사용하던 사람도 무엇이 원인인지 알기 어렵습니다.
어디가 문제인지 확인하기 위해 로그를 작성해 두었더라도 저장된 상태가 왜 이렇게 변경되었는지는 모든 로그를 보지 않는 한 찾기 어렵습니다.
하지만 저장되어있는 값에 따라 함수는 인자의 조건에 따라 문제가 없어보이던 코드도 문제가 발생할 수 있는 코드가 됩니다.
심지어 단순한 나누기 연산도 나누는 값에 따라 프로그램 전체에 panic을 줄 수도 있습니다. (`divide by zero`)

그런 점에서 상태 값은 문제가 될 수 있습니다. 정확히는 변경 가능한 상태 값이 문제가 됩니다.
함수에 같은 변수 값을 인자로 입력하더라도 상태 값에 따라 결과값이 매번 변경될 수도 있습니다.

어떤 방법에 문제가 있을 때 해결하기 위한 방법은 크게 두가지가 있습니다.
하나는 문제가 발생하더라도 컨트롤할 수 있도록 관리하는 방법이고,
다른 하나는 문제의 원인을 제거하는 방법입니다.

잘 컨트롤할 수 있도록 하는 방법이 객체지향 프로그래밍, 문제의 원인을 제거하는 방법이 함수형 프로그래밍입니다.

# 함수형 프로그래밍?
> 절차적 프로그래밍의 함수와는 함수의 ``이 다르다.
> 함수형 프로그래밍은 순수함수와 불변값을 사용해 소프트웨어를 만드는 기법입니다.
객체지향 프로그래밍은 그 이름대로 객체를 중심으로 생각해 개발합니다. 함수형 프로그래밍도 이름에서 알 수 있듯이 함수를 중심으로 생각해 개발하는 방법입니다.
객체지향 프로그래밍이 단순히 객체를 쓰기만 하면 객체지향인 것이 아닌 것처럼, 함수형 프로그래밍도 단순히 함수를 사용한다고 함수형 프로그래밍은 아닙니다.
절차적 프로그래밍에서 사용하는 함수와는 ``이 다릅니다.

절차적 프로그래밍에서도 함수를 정의하고 호출할 수 있지만 함수를 인자로 넘기거나 함수 내에서 함수를 생성하지 못합니다.
사실 함수를 인자로 넘기거나 함수 내에서 함수를 생성하는 것은 함수형 프로그래밍에서 특별한 것이 아닙니다.
객체지향 프로그래밍에서 필드값과 함수를 객체 내에서만 접근할 수 있도록 하고 인터페이스를 통해 메소드를 구현하는 것이 당연하듯이
함수형 프로그래밍에서도 당연하게 함수를 인자로 넘기고 함수 내에서 함수를 생성할 수 있습니다.

이 차이가 객체지향 프로그래밍과 함수형 프로그래밍의 차이를 만들어냅니다.
객체지향 프로그래밍에서는 함수의 인자나 객체의 필드로 `동작을 가지고 있는 객체`를 넘겨 함수 내부에서 동작을 호출하도록 만들었다면
함수형 프로그래밍에서는 함수의 인자로 `동작` 자체를 넘겨 조합해 실행합니다.

## 선언형 언어, 명령형 언어

먼저 짚고 넘어가야할 것이 함수형 프로그래밍은 객체지향 프로그래밍과 절차적 프로그래밍과는 구조가 다릅니다.

<center>
<img src="/assets/2022-03-17-TWL-02-2-FP/02-oop-fp.png" width="60%" alt="선언형 명령형 프로그래밍." />
</center>

선언형 언어로 대표적인 함수형 프로그래밍과 명령형 언어로 대표적인 객체지향 프로그래밍
{: style="text-align: center; color: gray; margin-top:.5em;"}

언어를 두가지로 나눠본다면 명령형 언어와 선언형 언어로 나눌 수 있습니다.
먼저 명령형 언어는 우리가 일반적으로 사용하는 프로그래밍 언어처럼 어떻게 동작해야하는지를 작성하는 언어입니다.
반대로 선언형 언어는 무엇을 표현하는 것인지를 작성하는 언어입니다.

명령형 언어만이 프로그래밍 방법은 아니지만 우리가 주로 사용하는 프로그래밍 언어들은 대부분 명령형 언어를 사용중입니다.
어셈블리 같은 기계 코드에서도 연산들이 명령형으로 작성되어있기 때문에 그것을 기반으로 만들어지는 프로그래밍 언어들에서 명령형
언어로 작성되는 것이 당연해보입니다.

<center>
<img src="/assets/2022-03-17-TWL-02-2-FP/03-html.jpeg" width="60%" alt="HTML" />
</center>

HTML은 프로그래밍 언어는 아닙니다...만! 선언형 언어입니다.
{: style="text-align: center; color: gray; margin-top:.5em;"}

그에 반해 선언형 언어로 주로 알려진 언어들은 `HTML``SQL`입니다. `어떤 작업을 해야한다` 보다는 `무엇을 보여준다`에 가깝습니다.
HTML는 헤더, 각 컴포넌트들을 통해 무엇을 화면에 보여줄 지를 표현하는 언어이고, SQL도 DB에서 읽어오는 작업 때문에
`어떻게 동작해야한다.`로 보이기도 하지만 `테이블 중에서 무엇을 보여준다`에 가깝습니다.

그렇다면 함수형 프로그래밍 언어는 `무엇을 보여준다`를 통해 어떻게 개발하는 걸까요?

### 함수형 언어?

기존 언어들에서는 `함수가 무슨 동작을 하는지` 정의하고 호출할 때 정의된 동작들을 실행했습니다.
함수형 프로그래밍에서는 동작을 정의하기보다는 `함수가 무엇인지` 정의하고 호출할 때 인자들을 정의된 값에 대입한다고 생각하면 편합니다.

```python
def fibo(n):
res = 1
while n > 1:
res *= n
n -= 1
return res
```
```haskell
fibo n
| n < 2 = 1
| otherwise = fibo(n-2) + fibo(n-1)
```

파이썬과 하스켈에서의 피보나치
{: style="text-align: center; color: gray; margin-top:.5em;"}

예를 들어 위의 파이썬 코드로 피보나치를 구현하면 입력 인자 n 을 받아 반복문을 돌면서 `res`값에 n을 곱하고 n을 1 감소시키는 동작을 반복하도록
구현할 수 있습니다. (물론 파이썬에서도 재귀로 작성할 수 있지만 함수형과의 차이를 더 크게 보여주기 위해)
하스켈에서의 코드는 n의 값에 따라 `동작할 명령어의 순서`를 정의하기보다는 n 값에 따라 함수의 결과에 `대입될 값`을 정의합니다.
n이 2보다 작을 때는 1을 대입하고 그 외에는 `fibo(n-2) + fibo(n-1)`을 대입하게 됩니다.

명령형 프로그래밍에서는 함수를 `실행해야할 동작들`로 보고 호출을 `실행한 결과를 반환하는 연산`으로 보지만
함수형 프로그래밍에서는 함수를 `인자에 따른 값`으로 보고 호출을 `인자가 입력되었을 때에 표현되는 값`으로 봅니다.
한가지 더 중요한 것은 함수에 인자를 넣을 때에서야 **lazy**하게 값이 **평가**된다는 것입니다.

```python
def add5(a):
return add(5, a)

def add(a, b):
return a + b

>>> add5(3)
8
```
```haskell
Prelude> add a b = a + b
Prelude> add5 = add 5
Prelude> add5 3
8
```

여기서 얻을 수 있는 장점은 함수에서 함수를 만들어내기 편하다는 점입니다. 함수를 lazy하게 평가되는 값으로 보기 때문에
함수에서 함수를 만들어내기 쉽습니다. lazy하게 평가되는 다른 값을 만들어내는 것이기 때문입니다.

위의 코드는 비슷하게 보이지만 동작은 꽤 차이가 있습니다. 두 코드 모두 `add5`를 호출해 계산하고 있는데,
파이썬 코드에서는 `add5`함수가 호출될 때, `add` 함수에 5와 `a`값을 입력해 호출하도록 동작합니다.
하지만 하스켈에서는 `add5``add` 함수에 5를 넣어 새로운 함수를 만듭니다.
그 후에 새로운 함수 `add5`에 3을 대입해서 계산을 합니다.

물론 하스켈과 똑같이 동작하도록 만들수도 있습니다.

```python
def add(a):
def _add(b):
return a + b
return _add

>>> add5 = add(5)
>>> add5(3)
8

# 하지만 add를 사용할 때는 아래처럼 사용해야 합니다.
>>> add(5)(3)
```

파이썬으로 하스켈과 비슷하게 동작하도록 작성한 코드를 보면 더 쉽게 이해할 수 있습니다.
위의 `add`함수를 보면 실제로 연산이 실행되는것은 `a``b` 모두 입력되었을 때입니다.

이것이 바로 lazy한 연산입니다. 실제로 값이 모두 주어졌을 때 계산하는 것입니다.

기존 프로그래밍 언어의 시각으로 생각해보면 `add``a` 인자를 넘기면 `a`라는 상태가 **불변으로 저장**되고,
이후에 `b`를 입력받아 + 연산을 한다고 이해할 수 있습니다.

## 함수형 프로그래밍의 특징

함수형 프로그래밍의 특징으로는 주로 아래 특징들이 꼽힙니다.

* 순수 함수
* 함수의 `결과가 파라미터에만 결정`되고 어떠한 `side effect도 일으키지 않는` 함수
* 함수를 실행할 때 `외부의 값을 접근하거나 수정`하지 않습니다. (이렇게 개발해야 좋다 라는 의미입니다)
* side effect가 있는 함수는 비순수 함수라고 합니다.
* 참조 투명성
* 인자가 같은 함수 호출을 함수의 결과로 대체할 수 있는 성질
* 순수 함수로 구현한다면 함수 결과로 대체하더라도 문제가 없습니다.
* 불변 데이터
* 인자로 입력한 데이터의 값을 변경시키지 않음
* 함수를 실행할 때 `파라미터의 값을 변경하지 않음`
* 일급 함수
* 함수를 파라미터로 사용하거나 반환값으로 사용하는 변수처럼 생각할 수 있는 특징
* 지연 평가
* 계산 결과가 필요할 때까지 연산을 늦추는 방법

명령형 프로그래밍 언어를 주로 사용하던 우리들에게 `상태를 변경하지 않고` 어떻게 구현할 지 감이 잘 오지 않습니다.

하지만 흔하게 사용하는 선언형 언어인 HTML을 생각해보면 `상태를 변경하지 않는 것`이 오히려 당연합니다.
HTML 코드에서 각 element가 내부 element 값을 변경한다는 것은 상상하기 어렵습니다.
또한 `element 구조가 같다면 항상 같은 모습의 화면`을 보여줄 것입니다.
만약 element 구조가 같은데 외부적인 요소에 의해서 HTML 구조가 달라진다면 화면을 구성하기 더 어려울 것입니다.
내부 값을 변경하는 대신 `여러 element를 조합해서 전체적인 구조`를 만들어냅니다.

함수형 프로그래밍에서도 마찬가지입니다. HTML처럼 `인자로 들어온 상태를 변경하지 않는 것`이 당연합니다.
함수에 인자로 들어온 `값을 변경하지 않고`, `함수의 인자가 같다면 같은 결과`를 내보내야 합니다.
그리고 인자나 변수의 값을 변경하는 동작 대신, `인자를 입력했을 때 여러 함수를 조합하여 원하는 값`을 만들어내는 것입니다.

### 순수 함수 (side effect가 없는 함수)와 참조 투명성
> 순수함수 = 결과값이 인자에 의해서만 결정 + side effect가 없음
순수 함수는 동일한 입력값을 받으면 같은 결과를 내보내고, 함수를 실행했을 때 값이 달라지는 `side effect`가 없는 함수입니다.
`side effect`란 값을 변경하는 행위입니다. 실제로 변수 값이 변경되지 않더라도 print를 찍어보거나 로그를 찍는 행위, 파일에 저장하는 행위는
외부의 값을 변경하기 때문에 `side effect`입니다. 또한 변수의 값을 assign 하는 행위, `set` 함수를 통해 reference의 값을 변경하는
행위 또한 `side effect`라고 할 수 있습니다.

객체지향 프로그래밍에서는 이런 `side effect`를 객체의 메소드에서만 수행하도록 만들어 `side effect`는 발생하더라도 어디서 문제가 발생한 것인지
비교적 쉽게 만들어줍니다. 하지만 함수형 프로그래밍에서는 애초부터 `side effect`를 허용하지 않는 순수함수를 사용하기를 권장합니다.

순수함수는 입력을 넣었을때 결과가 달라지도록 하는 어떠한 `side effect`도 발생시키지 않기 때문에 다음에 같은 인자를 넘긴다면
같은 결과를 내보냅니다. 참조 투명성은 이런 순수함수에서 함수를 다시 실행시키지 않고 결과값을 그대로 대입해도 같은 결과가 됨을 나타내는 성질입니다.
함수형 언어에서는 이 성질을 이용해 같은 결과를 여러번 이용해야하는 재귀 함수를 최적화하기도 합니다.

### 불변 데이터

불변 데이터는 말 그대로 변하지 않는 값입니다. 예를 들어 자바에서 `final`과 같은 키워드를 볼 수 있습니다.
값이 이후에 더이상 변경되지 않도록 보장하는 키워드입니다.

사실 객체지향 프로그래밍의 `private`에 해당하는 작업이 불변 데이터입니다. `private` 변수는 객체 내부에서만
값을 변경할 수 있도록 하지만 함수형 프로그래밍은 값을 아예 변경하지 못하도록 권장합니다.

### 일급함수

일급함수는 함수

## 함수형 프로그래밍의 기법들

함수형 프로그래밍의 개념만 보아서는 크게 핵심을 이해하기는 어렵습니다.


### 고차 함수

### 커링

### Partial Application

### 클로저


## Reference

* [https://wiki.haskell.org/Thunk](https://wiki.haskell.org/Thunk)
35 changes: 35 additions & 0 deletions _posts/2022-03-17-TWL-02-3-OOP-FP.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
---
layout: post
title: TWL-02 세번째. 어떻게 프로그래밍해야할까
subtitle: 객체지향, 함수형 프로그래밍을 어떻게 적용할지 이야기합니다.
categories: [TWL, CS]
tags: [TWL, CS, OOP, FP]
---

사실 객체지향 프로그래밍과 함수형 프로그래밍 모두 좋은 코드를 작성하기 위한 방법론입니다.
우리의 목적은 객체지향적으로 작성하거나 함수형으로 작성하는것이 아니라 좋은 코드를 작성하는 것이기 때문에
각 상황에 맞게 더 좋은 방법을 선택하면 됩니다.

# 어떻게 개발해야할까?

객체지향


## 동일한 문제를 어떻게 해결하는지


##

# 상태를 가지지 않고 개발할 수 있을까?





## Reference

* [http://www.incodom.kr/객체지향](http://www.incodom.kr/%EA%B0%9D%EC%B2%B4_%EC%A7%80%ED%96%A5)
* [https://velog.io/@phs880623/객치-지향-프로그래밍](https://velog.io/@phs880623/%EA%B0%9D%EC%B9%98-%EC%A7%80%ED%96%A5-%ED%94%84%EB%A1%9C%EA%B7%B8%EB%9E%98%EB%B0%8D)
* [https://coding-factory.tistory.com/328](https://coding-factory.tistory.com/328)
* [https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design](https://www.digitalocean.com/community/conceptual_articles/s-o-l-i-d-the-first-five-principles-of-object-oriented-design)
* [https://wiki.haskell.org/Thunk](https://wiki.haskell.org/Thunk)
15 changes: 10 additions & 5 deletions _sass/misc/article-menu.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
.post-menu {
padding-left: 20px;
min-width: 200px;
max-width: 230px;
max-width: 250px;

.post-menu-title {
font-size: $base-font-size * 1.5;
Expand All @@ -20,11 +20,16 @@
$indent: $base-font-size / 4;
$active-bgcolor: #ecebec;

@for $i from 2 to 7 {
@for $i from 1 to 7 {
.h-h#{$i} {
padding-inline-start: $indent + ($i - 2) * $base-font-size * 1.3;
font-size: $base-font-size * 1.1;
line-height: 1.4;
padding-inline-start: $indent + ($i - 1) * $base-font-size * 1.3;
@if $i < 4 {
font-weight: bold;
font-size: $base-font-size * (1.25 - $i * 0.08);
} @else {
font-size: $base-font-size * (1.1 - $i * 0.03);
}
line-height: 1.5em;
}
}

Expand Down
2 changes: 1 addition & 1 deletion _sass/yat/_layout.scss
Original file line number Diff line number Diff line change
Expand Up @@ -445,7 +445,7 @@ html {
display: block;
}

h2, h3, h4, h5, h6 {
h1, h2, h3, h4, h5, h6 {
margin: 60px 0 19px;
}

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/2022-03-17-TWL-02-1-OOP/02-apple-use.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/2022-03-17-TWL-02-2-FP/01-duggubi.gif
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/2022-03-17-TWL-02-2-FP/02-oop-fp.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added assets/2022-03-17-TWL-02-2-FP/03-html.jpeg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.