-
함수형 사고 (닐 포드 지음, 김재완 옮김)
-
자바스크립트로 알아보는 함수형 프로그래밍 (ES5) (인프런, 유인동)
-
새로운 프로그래밍 패러다임의 문제점은 새로운 언어를 배우는 것이 아님. 어려운 점은 바로 다른 방식으로 사고하는 법을 배우는 것.
-
함수형 코드를 작성하기 위해서는 문제에 접근하는 방식의 전환이 필요하다.
-
함수형 프로그래밍 같이 다른 패터다임을 익힐때 어려운 점은
-
새로운 빌딩블록을 배우고,
-
풀고자 하는 문제에서 그것이 해법이 될 수 있다는 점을 인지하는 것
-
-
대부분의 개발자들은 복잡한 비지니스 문제를 자바와 같은 어어로 번역하는 것이 그들의 할 일이라는 착각 속에서 일을 한다.
자바가 언어로서 유연하지 못하기 때문에, 아이디어를 기존의 고정된 구조에 맞게 주물러야 하기 때문이다.
-
문제를 프로그램에 맞추지 말고, 프로그램을 문제에 맞게끔 조정해가라.
-
고차함수들로만 코딩하면 좋은점은 코드 분리가 쉽다. (구조적 리팩토링이 쉽다.)
Note
|
문법적 설탕syntactic sugar
같은 의미의 코드를 간결하게 작성할 수 있게 해주는 언어 문법의 일종. 간결 표기법이라고도 함. |
-
자바가 메모리 관리 작업을 쉽게 해줬다면, 함수형 프로그래밍 언어는 다른 빌딩블록들을 고수준 추상적 개념으로 대체해준다.
-
OOP의 세계에서는 고유한 자료구조를 작성하는 것을 관장하나. 그 자료구조에 특정 통작을 메서드의 형태로 부착해서 말이다. 함수형 프로그래밍 언어는 같은 방식으로 재사용을 달설하여 하지 않고 최적화된 동작으로 몇몇 자료구조(list, set, map)를 이용하는 방식의 재사용을 선호한다.
-
함수형 개발자는 적은 수의 자료구조와 그것들을 잘 이해하기 위한 최적화된 방법을 만들기를 선호한다. 객체지향형 개발자는 항상 새로운 자료구조와 그것에 부착된 메서드를 만든다.
-
자바를 사용할 때는 null 때문에 문제가 많이 발생한다. null은 제대로 된 리턴 값인가, 아니면 값이 없다는 뜻인가? 스칼라를 포함한 많은 함수형 언어는 Option 클래스를 사용하여 이런 모호함을 피한다.
-
다른 함수형 언어들과 마찬가리고 스칼라는 null을 리턴한 것을 피하기 위해 관례적으로 Option을 사용한다.
함수형 프로그래밍
"함수형 프로그래밍은 애플리케이션, 함수의 구성요소, 더 나아가서 언어 자체를 함수처럼 여기도록 만들고, 이러한 함수 개념을 가장 우선순위에 놓는다."
마이클 포거스
/* 데이터(객체) 기준 */
dock.moveLeft();
duck.moveRight();
dog.moveLeft();
dog.moveRight();
/* 함수 기준 */
moveLeft(dog);
moveRight(duck);
moveLeft({ x: 5, y: 2 });
moveRight(dog);
"함수형 사고방식은 문제의 해결 방법을 동사(함수)들로 구성(조합)하는 것"
마이클 포거스
-
함수형프로그래밍은 값을 변경해나가면서 상태를 바꿈
-
함수형 프로그래밍은 부수 효과side effect를 미워하고 조합성을 강조하는 프로그래밍 패러다임
-
부수 효과를 미워한다. → 순수 함수를 만든다. → 오류를 줄이고 안정성을 높힘
-
조합성을 강조한다 → 모듈화 수준을 높힌다. → 생산성을 높힌다.
-
-
좋아지는 하드웨어 성능, 컴파일러
순수 함수
-
순수 함수pure function는 부수 효과가 없는 함수. 수학적 함수.
function add(a, b) { return a + b; }
-
들어온 인자가 같으면 항상 동일한 결과를 리턴.
순수 함수 X, 동일한 결과를 주었을 때 상황에 따라 다른 결과를 리턴하는 함수.var c = 10; // 이것이 상수라면 순수함수, 아니라면 순수함수라고 볼 수 없음 function add2(a, b) { return a + b + c; } console.log(add2(10, 2)); c = 20; console.log(add2(10, 2));
-
함수가 받은 인자외에 다른 어떠한 상태에 영향을 끼치지 않은 함수.
순수 함수 X, 부수효과를 일으키는 함수. 외부의 상태를 변경, 들어온 인자의 상태를 변경.var c = 10 function add3(a, b) { c = b; // 부수효과 return a + b; } console.log(c) // 10 console.log(add3(20, 30)) // 50. 결과는 동일하지만... console.log(c) // 30. 외부 상태가 변경됨 console.log(add3(20, 30)) // 50
순수 함수 X, 외부 상태를 변경하는 함수.val obj1 = { val: 10 }; function add3(obj, b) { obj.val += b; } console.log(obj1.val); // 10 add4(obj1, 20) console.log(obj1.val); // 30
-
순수 함수는 평가 시점이 중요하지 않음.
val obj1 = { val: 10 };
function add5(obj, b) {
return { val: obj.val + b }
}
console.log(obj1.val)
val obj2 = add5(obj1, 20)
console.log(obj1.val);
console.log(obj2.val);
일급 함수
-
first class function. 함수를 값으로 다룰 수 있다는 것
-
JS에서는 함수가 일급함수
-
언제 평가해도 상관 없는 순수 함수와 일급 함수를 통해 함수의 조합성을 높혀나가는 것.
function add(a, b) { return a + b; };
val f1 = function(a) { return a * a; };
console.log(f1);
val f2 = add
function f3(f) {
return f();
}
console.log(f3(function() { return 10; })); // 10
console.log(f3(function() { return 20; })); // 20
고차 함수
-
filter: 주어진 조건에 맞는 컬렉션의 부분집합 구하기
-
map: 컬렉션을 그 자리에서 변형하기
-
recude, fold: 컬렉션의 요소를 하나씩 다른 함수로 처리하기
Note
|
캐터모피즘catamorphism
카테고리 이론의 개념으로 목록을 접어서 다른 형태로 만드는 연산을 총칭한다. |
Note
|
플래트닝falttening
평탄화. 중첩을 펼치는 연산. |
클로저
-
모든 함수형 언어는 클로저를 포함한다.
-
클로저closure란 그 내부에서 참조되는 모든 인수에 대한 뭊시적 바인딩을 지닌 함수를 칭한다.
-
이 함수는 자신이 참조하는 것들의 문맥context를 포함한다.
-
-
클로저란 단어의 어원리 문맥을 포괄함enclosing context이란 점에서 이 작업의 내용을 추측할 수 있을 것이다.
-
클로저는 지연 실행deferred execution의 좋은 예다.
function add_maker(a) {
return function(b) { // (1)
return a + b;
}
}
-
a
를 기억하는 클로저. 또한, 순수함수
커링과 부분 적용
-
커링과 부분 적용은 20세기 수학자인 해스컬 커리Haskell Curry 등의 작업을 통해 수학에서 유래한 언어 기술이다.
-
커링이나 부분 적용은 함수나 메서드의 인수의 개수를 조작할 수 있게 해준다.
-
주로 인수 일부에 기본값을 주는 방법을 사용한다.
이를 인수 고정이라고도 부른다.
Note
|
커링currying
다인수multi-argument 함수를 일인수single-argument 함수들의 체인으로 바꿔주는 방법. 이것은 변형 과정이나 변형된 함수를 실행하는 것을 지징하는 것은 아님. |
Note
|
부분 적용partial application
주어진 다인수 함수를 생랼될 인수의 값을 미리 정해서 더 적은 수의 인수를 받는 하나의 함수로 변형하는 방법. 이 방법은 이름이 의미하듯이 몇몇 인수에 값을 미리 적용하고 나머지 인수만 받는 함수를 리던한다. |
-
커링은 체인의 다음 함수를 리턴.
부분 적용은 주어진 값을 인수에 바인딩시켜서 인수가 더 적은 하나의 함수를 만듬. -
process(x,y,z)
의 완전히 커링된 버전은process(x)(y)(z)
.첫 인수만 커링을 하면
process(x)
의 리턴 값은 인수가 하나인((y)
) 또 하나의 함수다. 이 함수의 리턴 값은 또 하나의 일인수 함수다. -
부분 적용을 사용하며 변환하면 인수 숫자가 적은 함수가 남는다.
process(x,y,z)
의 인수 하나를 부분 적용하면 인수 두 개짜리인process(y,z)
가 된다.
메모이제이션
-
메모아이즈된 함수의 결과가 매개변수 이외의 어떤 것에라도 의존하면 기대하는 결과를 항상 얻을 수는 없다.
-
메모아이즈된 함수는 부수효과가 없어야 한다.
Note
|
메모이제이션memorization
|
게으름
-
표현의 평가를 가능한 최대로 늦추는 기법인 게으른 평가는 함수형 프로그래밍 언어에서 많이 볼 수 있는 기능이다.
-
엄격한지strict 혹은 관대한지nonstrict(게으른지)
-
게으름의 이점
-
무한수열을 만들 수 있음. 값을 평가하지 않아도 되기 때문.
-
저장시 크기가 줄어듬. 컬렉션 전부를 유지하지 않고 순차적으로 다음 값을 유도할 수 있으니.
-
런타임이 좀 더 효율적은 코드를 만들 수 있음
-
Note
|
추상 구문 트리abstract syntax tree, AST
|
100개의 함수를 하나의 자료구조에 적용하는 것이 10개의 함수를 10개의 자료구조에 적용하는 것보다 낫다.
연산자 오버로딩
-
함수형 언어의 공통적인 기능은 연산자 오버로딩이다.
-
스칼라에서 연산자는 특별한 이름을 가진 메서드에 불과하다.
-
새로운 언어를 만들지 말고, 연산자 오버로딩을 통해 문제 도메인을 향하여 언어를 구부리자.
함수형 자료구조
-
대부분의 함수형 언어들은 예외 패터다임을 지원하지 않기 때문에 개발자는 다른 방법으로 오류 조건을 표현해야 한다.
-
예외는 많은 함수형 언어가 준수하는 전제 몇 가지를 깨뜨린다.
-
함수형 언어는 부수효과가 없는 순수함수를 선호한다. 예외를 발생시키는 것은 예외적인 프로그램 흐름을 야기하는 부수효과다.
-
함수형 언어들은 주로 값을 처리하기 때문에 프로그램의 흐름을 막기보다는 오류를 나타내는 리턴 값에 반응하는 것을 선호한다.
Note'이펙티브 코틀린 - 아이템 7’에서 실패는 나타내는
sealed
클래스(일반적으로Failuer
)를 사용하라는 얘기가 있는데, 함수형 언어에서 예외를 던지는 것보다 '오류를 나타내는 리턴 값’이 이와 비슷한 의미지 않을까?
-
Either 클래스
-
함수형 언어에서 다른 두 값을 리턴해야하는 경우가 종종 있는데 그런 행동을 모델링하는 자료구조.
-
Either
는 왼쪽 또는 오른쪽 값 중 하나만 가질 수 있게 설계됨. -
이런 자료구조를 분리합집합disjoint union이라고 함
-
자바에서
Optional
?
코틀린에서Pair
는 아닌 것 같음. 부분집합? 구현체? 라고도 볼 수 있어 보임. -
함수형의 보편적인 관례에 따라
Either
클래스의 왼쪽이 예외, 오른쪽이 결과 값. -
여러 프레임워크에
Either
와 유사한Option
이란 클래스가 있다.
Option
은Either
의 간단한 부분집합이라고 볼 수 있음.
Either
는 어떤 값이든 저장할 수 있는 반면,Option
은 주로 성공과 실패의 값을 저장하는데 쓰임.
모나드
디자인패턴
-
함수형 언어계의 어떤 이들은 디자인 패턴이 개념 자체에 결함이 있기 때문에 함수형 프로그래밍에서는 필요가 없다고 주장한다. 패턴의 좁은 정의만 볼 때에는 일리가 있는 말이다. 아지만 그런 주장은 패턴의 사용보다는 의미론에 국한된 것이다.
-
디자인 패턴의 개념은 아직도 건재하다. 하지만 다른 패러다임에서 패턴들은 다른 형태로 나타난다.
자바
Note
|
SAM, single abstract method
단일 추상 메서드. Java에서 |
-
Runnable
,Callable
같이 메서드를 하나만 가지는 인터페이스를 단일 추상 메서드라 부름 -
하나의 함수형 인터페이스는 하나의 SAM을 포함하며, 여러 개의 디폴트 메서드도 함께 포함할 수 있다.
-
함수형 인터페이스는 기존의 SAM 인터페이스가 전통적인 익명 클래스 인트턴스를 람다 블록으로 대체할 수 있게 해준다.
-
자바 8에서는 인터페이스에 디폴트 메서드를 지정할 수 있다.
(디폴트 메서드는 순수 함수가 아닐까?) -
자바 8읠 디폴트 메서드는 자바에 믹신을 제공한다. 이 덕분에
Arrays
,Collections
같은 클래스들을 JDK에서 없앨 수 있게 된다. 이것들은 적당한 자리를 찾기 못한 정적 메서드의 모임에 불과했기 때문이다.
Note
|
mixin
다른 클래스에서 사용될 메서드를 정의하지만, 그 클래스의 상속 체계에 포함되지 않은 클래스를 지칭한다. 코드의 재사용성을 권장하고 다중상속의 모호함을 해결해준다. 믹신은 플레이어버스 언어에서 시작되었는데, 아이스크림 가게에서 영감을 받았다고 한다. 평범한 맛의 아이스크림에 손님이 원하는 '믹스-인'(사탕 조각, 땅콩 등)을 가미해서 판매했다. |
-
스트림은 여러모로 컬렉션과 비슷하지만 다음과 같은 차이점이 있다.
-
스트림은 값을 저장하지 않으며, 종결 작업을 통해 입력에서 종착점까지 흐르는 파이프라인처럼 사용된다.
-
스트림은 상태를 유지하지 않는 함수형으로 설계되었다.
-
스트림 작업은 최대한 게으르게 한다.
-
무한한 스트림이 가능하다.
-
Iterator
인스턴스처럼 스트림은 사용과 동시에 소멸되고, 재사용 전에 다시 생성해야 한다.
-
함수형 인프라스트럭처
아키텍처
-
함수형 아키텍처는 불변성이 그 중심에 있고, 이를 최대한 사용하려 시도한다.
-
불편 클래스는 자바에서 주로 걱정해야 하는 것들을 많이 없애준다.
-
테스트의 진정한 목적은 변이mutation를 확인하는 것이고, 변이가 많을수록 테스트가 많이 필요하게 된다.
-
불편 클래스들은 생성 시에만 변화가 있기 때문에 테스트가 간단한다.
-
불변 객체는 변경을 허용하지 않으므로 컬렉션의 키로도 안성맞춤이다.
-
불변 객체는 가동적으로 스레드 안전하기 때문에 동기화의 문제가 없다.
CQRS
-
그레그 영(Greg Young)이 개념을 도입했고, 마틴 파울러가 영향력 있게 그 개념을 기술했다.
-
전통적인 어플리케이션 아키텍처에서는 모델 부분이 비지니스 규칙이나 검증을 담당한다.
-
읽기/쓰기의 홉합된 의미를 모델 전역에서 관리해야하고 이것이 시스템을 복잡하게 한다.
-
-
CQRS는 읽기와 명령 부분을 분리함으로써 아키텍처의 일부를 단순화한다.
-
쿼리 모델
-
개발자가 불변성을 가정할 수 있기 때문에 쿼리 쪽의 논리는 훨씬 단순하다.
-
-
커맨드 모델
-
-
CQRS를 사용하면 트랜잭션형보다는 최종 일관성 모델로 전환해야 할 것이다.
Note
|
최종 일관성(eventual consistency)
최종 일관성 분산 컴퓨팅 모델은 모델을 업데이트하는 데 정해진 시간 제한을 요구하지 않는다. 대신 새로운 업데이트가 없는 한, 최종적으로 모델이 일관성을 갖추기만 하면 된다. 트랜잭션 모델이 ACID에 의존하는 반면, 최종 일관성 모델은 BASE를 중요하게 여긴다.
|
데이터베이스
-
관계형 데이터베이스에서 파괴적 업데이트를 하는 의도는 무엇일까?
-
다시 말해, 업데이트할 때마다, 예쩐 값은 없어지고 새 값으로 대체된다는 뜻
-
-
데이터가 증가하는 것을 억제하고 저장 장소를 극대화하기 위해서다.
-
하지만 이제 세상이 바뀌었다. 컴퓨팅 자원은 이제 가격이 낮다.
폴리글랏
-
함수형 프로그래밍 패러다임은 문제와 그것을 푸는 데 사용되는 도구에 관한 사고의 틀이라고 할 수 있다.
-
많은 현대 언어들은 폴리패러다임(혹은 멀티패러다임)이다.
-
이들을 객체지향, 함수형, 절차형 등 몇 가지 서로 다른 프로그래밍 패러다임을 지원한다.
-
멀티패러다임 언어는 개발자가 각 패러다임을 적재적소에 사용할 수 있다는 엄청난 이점이 있다.
-
객체지향 언어에서는 코드 재사용이 구조 중심이지만, 함수형 언어에서는 구성과 고계함수 중심이다.