일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- 에릭 노이먼
- 로버트 C마틴
- 큰돌의 CS책
- 이웅모
- 함수형 코딩
- 클린코드다시읽기
- https://product.kyobobook.co.kr/detail/S000001952246
- 리엑트를 다루는 기술
- 쏙쏙 들어오는 함수형 코딩
- 출처 : 코딩앙마
- 생코님Redux
- 출처 : 코딩애플
- 오종택개발자님
- 유틸리티타입은 공식문서 자주 보자
- 출처 : 자바스크립트 딥다이브
- 에릭 노먼드
- 김영한쌤
- 흥달쌤
- 출처 : https://www.boostcourse.org/
- 출처는 코딩앙마
- 출처는 코딩애플
- 갈길이 멀구나
- 쏙쏙 들어오는 함수형코딩
- 쏙속 들어오는 함수형코딩
- 에릭노이먼
- 고등애플
- 나는 flux좋아...
- 출처 : 한입크기로 잘라먹는 타입스크립트
- 쏙쏙들어오는함수형코딩
- 자바스크립트 딥다이브
- Today
- Total
틈틈히 메모중
[#5] 복잡성을 줄이는 디자인 패턴 본문
🧡 명령형 에러 처리 체계의 문제점
try-catch문으로 예외처리를 하는 것은
1. 함수 합성과 체이닝을 할수 없게 하고
2. 동일 input일때 동일한 output을 낸다는 참조 투명성원리에 위배되며,
3. 부수효과발생가능성
4. 에러발생시 호출지점을 벗어나 비지역성 non-locality원리에 위배
5. catch문안에서 특정 예외를 처리하는데에도 에너지를 써야 하기 때문에 호출자 부담 증가
6. 에러 조건 처리 블록들이 중첩되어 사용하기 어려움
예외처리는 적재적소에 쓰면 가장 좋다.
🧡 컨테이너로 잘못된 데이터 접근을 차단
값을 컨테이너화 해서 값을 안전하게 다루고, 프로그램 불변성이 지켜지도록 직접적인 접근 차단하기
//값을 함수형 자료형으로 감싸기
class Wrapper {
constructor(value){
this._value = value;
}
//map :: (a->b) -> a -> b
map(f){
return f(this._value);
}
toString(){
return `Wrapper ( ${this._value} )`;
}
}
//wrap :: a -> Wrapper(a);
const wrap = value => new Wrapper(value);
const 실험1 = wrap('함수형가즈아');
실험1.map(R.indentity); // '함수형가즈아
const 실험2 = wrap(null);
실험2.map(doWork); // doWork가 null체크 해야 null값 거를수있음
위 함수에서 map을 변형하여, 함수 호출전에 null이나 빈문자열 등 체크해보기
//Wrapper클래스 안에 추가하기
//fmap :: (a -> b) -> Wrapper[a] -> Wrapper[b]
fmap(f){
return new Wrapper(f(this.value));
}
fmap 은 "함수자"이다.
fmap은 함수와 (a->b), 함수자(감싼 컨텍스트 Wrapper(a)를 받아서 새로운 함수자 Wrapper(b)를 반환함
🧡 함수자 를 자료 변환 도구로 활용
const add = R.curry((a,b) => a + b);
const add3 = add(3);
const two = wrap(2);
const five = two.fmap(add3); //Wrapper(5)
five.map(R.identity) // 5
//fmap은 같은 형식을 반환함 = 체이닝할수있는 조건 만족
map, filter도 결국 함수자이다.
함수자가 되려면
1. 부수효과가 없어야 함
2. 합성이 가능해야함
3. mapping기능을 제공해야함 (함수자 안에 있는 값을 함수로 변환할수있어야 함)
🧡모나드는 합성을 촉진하는 자료형
모나드 ? 순수함수에서 side effect를 다루고 값의 흐름을 추상화 하기 위한 디자인 패턴, 모델
- 값을 감싸고 있어 컨테이너처럼 동작함
- 값에 대한 연산을 순차적으로 캡슐화 하고, 각 연산의 결과를 다음연산에 전달하는 방식으로 흐름을 추상화함
- 결과를 다시 모나드로 반환함
- 일정 법칙을 따름
=> Maybe모나드, Either모나드, Promise모나드, State모나드...
🧡 에러 처리 전략을 모나드 형에 통합
Maybe 모나드 ? 값이 존재할수도 있고, 존재 하지 않을수도 있는 상황을 다룸 (널 포인터 예외를 방지하기)
// Maybe 모나드 구현
const Maybe = (value) => ({
map: (fn) => (value ? Maybe(fn(value)) : Maybe(null)),
value: () => value,
});
// 사용 예시
const user = { name: 'Alice', age: 30 };
const getName = (user) => user.name;
const maybeUser = Maybe(user);
const maybeName = maybeUser.map(getName);
console.log(maybeName.value()); // 'Alice'
//Maybe모나드와 그 하위형 Just, Nothing
class Maybe{
static just(a){//주어진 값을 포함하는 Just모나드 생성
return new Just(a);
}
static nothing(){ //아무것도 없는 Nothing모나드 생성
return new Nothing();
}
static fromNullable(a){ //값이 존재하면 Just 모나드를, 그렇지 않으면 Nothing 모나드를 생성
return a != null ? Maybe.just(a) : Maybe.nothing();
}
static of(a){ //just(a)와 동일한 역할
return just(a);
}
get isNothing() {//현재 모나드가 Nothing인지 여부를 나타내는 속성
return false;
}
get isJust(){ //현재 모나드가 Just인지 여부를 나타내는 속성
return false;
}
}
class Just extends Maybe{
constructor(value){//Just 모나드를 생성할 때 사용하는 생성자입니다. 값을 포함
super();
this._value = value;
}
get value(){ //현재 Just 모나드에 포함된 값을 반환
return this._value;
}
map(f){ //현재 Just 모나드에 함수를 적용하고, 그 결과를 새로운 Just 모나드로 감싸서 반환
return Maybe.fromNullable(f(this._value));
}
getOrElse(){//현재 Just 모나드에 포함된 값을 반환
return this._value;
}
filter(f){//현재 Just 모나드에 필터 함수를 적용하고, 조건을 만족하지 않으면 Nothing 모나드를 반환
Maybe.fromNullabe(f(this._value) ? this._value : null);
}
chain(f){//현재 Just 모나드에 함수를 적용하고, 그 결과를 반환
return f(this._value);
}
toString(){
return `Maybe.Just(${this._value})`;
}
}
class Nothing extends Maybe{
map(f){ //현재 Nothing 모나드를 그대로 반환
return this;
}
get value(){ //Nothing 모나드는 값을 포함하지 않으므로 값을 가져올 수 없다고 표시해줌
throw new TypeError('Nothing값을 가져올수 없습니다.');
}
getOrElse(other){ //대체값(other)을 반환
return other;
}
filter(f){ //값이 존재하고, 주어진 함수를 만족하면 해당 값이 담긴 Just반환, 그외에는 Nothing반환
return this._value;
}
chain(f){ //현재 Nothing 모나드를 그대로 반환
return this;
}
toString(){
return `Maybe.Nothing`;
}
}
Either 모나드 ? 두가지 중 하나의 값을 나타냄 ( 예외처리와 오류관리에 유용 )
// Either 모나드 구현
const Left = (value) => ({
map: (fn) => Left(value),
value: () => value,
});
const Right = (value) => ({
map: (fn) => Right(fn(value)),
value: () => value,
});
// 사용 예시
const divide = (a, b) => (b === 0 ? Left('Division by zero') : Right(a / b));
const result1 = divide(10, 2); // Right(5)
const result2 = divide(10, 0); // Left('Division by zero')
console.log(result1.value()); // 5
console.log(result2.value()); // 'Division by zero'
class Either{
constructor(value){
this._value = value;
}
get value)(){
return this._value;
}
static left(a){
return new Left(a);
}
static right(a){
return new Right(A);
}
static fromNullable(val){
return val !== null && val !== undefined ? Either.right(val) : Either.left(val);
}
static of(a){
return Either.right(a);
}
}
class Left extends Either {
map(_){
return this; //쓰지 않음
}
get value(){
throw new TypeError("Left(a) 값을 가져올 수 없습니다.");
}
getOrElse(other){
return other;
}
orElse(f){
return f(this._value);
}
chain(f){
return this;
}
getOrElseThrow(a){
throw new Error(a);
}
filter(f){
return this;
}
toString(){
return `Either.Left(${this._value})`;
}
}
class Right extends Either {
map(_){
return Either.of(f(this._value));
}
getOrElse(other){
return this._value;
}
orElse(f){
return this; // 쓰지 않음
}
chain(f){
return f(this._value);
}
getOrElseThrow(_){
return this._value;
}
filter(f){
return Either.fromNullable(f(this._value) ? this._value : null);
}
toString(){
return `Either.Right(${this._value})`;
}
}
Promise 모나드 ? 비동기 작업을 추상화함 (js의 내장 Promise객체가 Promise모나드의 예시 )
// Promise 모나드 사용
const fetchData = () => new Promise((resolve, reject) => {
setTimeout(() => {
resolve('Data fetched successfully');
}, 1000);
});
fetchData()
.then((data) => {
console.log(data); // 'Data fetched successfully'
})
.catch((error) => {
console.error(error);
});
State 모나드 ? 상태(state)를 가지고 있고, 그 상태를 변환하는데 사용(불변성 유지에 유용)
// State 모나드 구현
const State = (updateFn) => ({
map: (fn) => State((state) => {
const [newValue, newState] = updateFn(state);
return [fn(newValue), newState];
}),
});
// 사용 예시
const increment = State((state) => [state + 1, state]);
const [result, newState] = increment
.map((value) => value * 2)
.map((value) => value + 10)
.map((value) => value - 5)
.map((value) => value ** 2)
.map((value) => value.toString());
console.log(result); // '36'
🧡 모나드형의 교차 배치 및 합성
const map = R.curry((f, container) => container.map(f);
const chain = R.curry((f, container) => container.chain(f);
'함수형 프로그래밍 > 함수형 자바스크립트' 카테고리의 다른 글
[#7] 함수형 최적화 (4) | 2023.09.14 |
---|---|
[#6] 테스트와 함수형프로그래밍 (0) | 2023.09.12 |
[#4] 재사용 가능한, 모듈적인 코드로 (0) | 2023.09.05 |
[#3] 자료구조는 적게, 일은 많이 (0) | 2023.09.01 |
[#2] 고계 자바스크립트 (0) | 2023.08.30 |