FP(Functional Programming) - Reader

ㅎㄱㅎ·2020년 10월 19일
0

Reader monad

실행 하면서 상태(config) 같은걸 읽을 수 있도록 하는 모나드 입니다.

const config = {conf: true}
function fn1(){...}
function fn2(){
	if(config.conf) ...
}

이렇게 되면 함수의 순수성도 깨지게 되고, 코드가 길어지고 많아지면 코드 파악이 쉽지 않고
결과적으로 실수가 발생 할 수 있습니다. 

함수를 mapping 하면서 필요 할 때 가져다가 읽어오는 기능을 갖는게 Reader 모나드 입니다.

Reader 모나드의 interface

map이나 chain은 사실 either나 mayber와 대동소이 하지만 ask라는 특이한 함수가 있습니다.
이 함수는 입력된 설정을 읽어와 다음 매핑된 함수의 파라미터로 넘길 수 있도록 하는 함수 입니다.

Reader 모나드의 구현

runReader함수는 생성때 입력된 함수 입니다. env를 받아 T 타입의 값을 리턴 하네요, 처음 reader 모나드를 생성 할 때는 파라미터가 없기 때문에 ?가 붙어 있습니다.

map 함수는 env를 받아서 mapping된 함수와, 해당 모나드의 runReader를 합성하여 리턴하는 함수를 새로운 모나드의 runReader 함수로 등록 합니다.

ask 함수는 identity 함수를 등록합니다. env가 입력 되면 env를 값으로 리턴 할거 같다는 추측을 해볼 수 있습니다.

말로 설명하니 너무 복잡하네요.. ㅜ

runReader : () => 10 // 시작 
map f: v => v + 10 ~> runReader((env)=> f(()=>10));
map g: v => v + 20 -> runReader((env) => g((env) => f(() => 10)));

이런식으로 reader 모나드를 생성하면서 전에 있던 reader 모나드의 
runReader를 합성 합니다. 여기서 runReader(99) 을 호출 하게 되면 아래와 같이 실행 됩니다.

runRader((99) => g((99) => f(() => 10))); 시작 함수의 리턴값
runReader((99) => g((99) => 20); 
runReader((99) => g(20);
runReader(40); 

다시 코드를 보면
runReader : () => 10 // 시작 
map f: v(10) => v + 10 ~> runReader((99)=> f(()=>10));
map g: v(20) => v + 20 -> runReader((99) => g((99) => f(() => 10)));

이렇게 mapping 함수의 리턴값이 다음 map 함수의 파라미터로 연계가 됩니다.

ask 함수를 한번 보겠습니다.

runReader : () => 10 // 시작 
map f: v(10) => v + 10 ~> runReader((99)=> f(()=>10));
map g: v(20) => v + 20 -> runReader((99) => g((99) => f(() => 10)));
ask() -> id(99) // 99
 - 위의 ask 코드를 보면 직전 mapping 결과를 받지만 따로 리턴하지 않습니다. 
 오직 env만 리턴 합니다
map h : v(99) => v + 3
 

예제

이런식으로 ask로 읽어서 mapping 하는 것들을 여러 벌 만들고 chain으로 합성하게 되면 진행 중에 언제든지 ask를 읽는 것이 되겠네요

이걸 어디에다 쓰는 걸까요.. 생각 해 봐야 겠습니다 ..

profile
dog발자

0개의 댓글