기본 콘텐츠로 건너뛰기

1월, 2023의 게시물 표시

Array.map?

지난 글에 haskell에서 정의한 functor는 아래와 같다고 하였다.   fmap :: (a -> b) -> fa -> fb  해석을 하면  1. a를 받아 b를 리턴하는 함수를 인자로 받는다.  2. a가 담긴 functor를 받아 b가 담긴 functor를 리턴한다. 자 일단 배열은 functor이고, 위와 같이 작성해보면, map :: (a -> b) -> [a] -> [b ]  1. a를 받아 b를 리턴하는 함수를 인자로 받는다.  2. a가 담긴 배열을 받아 b가 담긴 배열을 리턴한다.  이제야 배열이 functor라는 것을 순환 없이 이해 할 수 있게 되었다. 자 그러면 배열처럼 값을 순환해주는 functor를 작성해보도록 하자. function Stream (value) { this . value = value?.[ Symbol . iterator ] ? value : [] this . map = function (cb) { const res = [] for ( const v of this . value ) { res. push (cb(v)) } return new Stream (res) } } new Stream ([ 1 , 2 , 3 ]). map (x => x) // ~ [1, 2, 3] new Stream ([ 1 , 2 , 3 ]). map (x => x). map (x => x * 2 ) // ~ [2, 4, 6]  이름을 Stream으로 작성해보았다.  배열의 map과 달리 나의 경우에는 Symbol.iterator를 기준으로 삼았기에 아래와 같은 작업도 가능하게 되었다. new Stream ( '123' ). map (x => x) // ~ [1, 2, 3] new Stream ( null ). map (x => x) // ~ [] new Stream (). map (x => x) // ~ []   이

Functor.map?

 배열은 펑터인가? 맞다. map함수가 있으니 맞다. 그러면 map이 무엇인가? 사실 우리는 map이라는 함수를 만나기 전부터 map이라는 단어를 프로그래밍하는 도중 만난적이 있다.  Map이라는 자료 구조인데 키와 값을 같은 자료 구조이다. Map이라는 자료 구조자체가 키에 값을 대응시킨다. 라는 매핑에서 따서 만들어 진 자료구조일 것이다.  사실 자료구조에서 Map과 Functor.map은 같은 단어이다. 지난 내용으로 범주론을 설명하면서 A범주에서 B범주로 대응시키는 것이다. 함자라고 하였다. 그리고 그 대응시키는 함수가 사상(map)이라고 부른다.  자 그러면 오해를 풀어보자. 우리가 생각하는 map?  [1, 2, 3, 4].map( x => x + 1 ) 이 문장을 보면 우리는 배열의 데이터를 순환하면서 1씩 더해주는 무언가로 보기 때문에, map에서 순환이라는 내용을 내려놓기 힘들다.  하스켈에서 정의한 Funtor는 무엇일까?   fmap :: (a -> b) -> fa -> fb  해석을 하면  1. a를 받아 b를 리턴하는 함수를 인자로 받는다.  2. a가 담긴 functor를 받아 b가 담긴 functor를 리턴한다.    자바스크립트로 구현하면 위의 내용은 어떤 모양일까? function Functor (value) { this . value = value this . map = function (cb) { return new Functor (cb( this . value )) } }  간단하게 Functor를 구현해볼 수 있다. 당연하게도 배열을 넣게 되면 그 배열을 제대로 순회하지 못할 것이라는 것을 알 것이다. 그 부분은 다음 장부터 한번 풀어보도록 하자.  학습하면서 진행하는 블로그이며, 함수형 프로그래밍과 관련된 내용을 마치고 나서 이 산이 아닌가벼... 하면서 잘못된 내용을 전파할 수 있으니 참고 하도록 하자.

Functor?

  Functor가 무엇일까? Array가 Functor라는 말은 들어보았을 것이다. 뭐 다들 그러니 Functor가 맞을 것이다. 그러면 Array는 왜 Functor이고 Functor라고 말할 수 있는 최소 조건은 무엇일까? 한 번 확인해보자.  Functor  Functor는 데이터 타입이다. 뭐 Array도 데이터 타입이니 놀랄 내용도 아니다. Functor는 어떤 값을 가지고 있는 컨테이너 성격의 데이터 타입이며, 해당 값에 함수를 적용 할 수 있어야 한다. 우리가 Array안에 있는 값을 map으로 특정 함수를 적용 시키는 것과 마찬가지라고 보면 된다.  자주 들어보았을 법한 내용으로 map을 가지고 있는 객체라면, 펑터라고 보아도 된다고 많이 들었을 것이다. map이 무엇을 뜻하는 걸까? 간단하게 Array에서의 map은 내부의 값들을 순회하며, 함수를 적용하고 출력을 해주는 함수이다.  간단한 내용을 언급하자면, 내부의 값은 Functor아 아니다. 일반적으로 [1, 2, 3, 4], [true, true, false, true] 등등 원시 값들을 순회 한다고 쳐보자. 당연학게도, 숫자나 진위 값들이 map을 지원 할 리 없으니 Functor가 아니다.  ( 뭐 물론, 2차원 이상의 배열을 순회시 내부의 값은 배열들 일테니, Functor겠지만, 일반적인 상황을 따지자.)  뭐 간단하게 Functor가 무엇인지, 아직까지는 감이 안 올 수 있다. 감이 오는게 이상 할 것이겠지만....  Functor는 왜 어려울까? 어려운 거니까 어렵다.  Functor(함자)  뭐 물론 Array는 Functor이다. 이런식의 설명만 하고 마친다면 꽤나 쉬울 만한 내용일 것이다. 하지만 조금만 더 들어가보자.  함자를 설명하기 위해서는 범주론 을 간략하게나마 설명 하고자 한다. 뭐 물론 내 설명에 틀린 내용도 있을 수 있고, 많이 생략된 내용이여서 이해가 더 안 갈 수 있다. 하지만 필요한 키워드에 굵게 칠해 둘테니 그 내용을 확인 하기 바란다.   범주론 (

reduce (함수형 프로그래밍)

  지난 주제에 reduce를 소개를 하였다.  reduce를 이용하여, map, filter, compose등 여러 함수를 만들 수 있는 것을 볼 수 있었을 것이다.  뭐 눈치는 챘겠지만 함수형 프로그래밍을 공부를 하기 위하여 작성하는 포스팅들이다. 하지만, 지난번에 작성한 reduce는 아쉬운 점이 있다. for문을 사용 하였다는 것이다.  for문이 뭐가 문제인가? 라는 생각을 할 수 있겠지만, 많은 함수형 프로그래밍 언어에서는 for, while ~ do와 같은 장치는 지원하지 않는 다는 것이다. 반복문 없이 코드를 어떻게 작성하냐 싶겠지만, 우리는 모두 안다. 재귀를 사용하면 된다는 것을....  그렇다 이번에는 reduce를 재귀를 이용하여 작성을 해보려고 한다.  reduce 재귀함수 ver. function reduce ( arr , reducer , initValue ) { if ( !arr. length ) return initValue const currentValue = arr. shift () initValue = reducer( currentValue , initValue ) return reduce ( arr , reducer , initValue ) }  재귀 함수로 코드를 작성하고자 한다면 위와 같이 작성 할 수 있을 것이다. const arr = [ 1 , 2 , 3 , 4 ] reduce(arr , (c , a) => c + a , 0 ) // 10 console.log(arr) // []  정상적으로 잘 작동 하는 듯 하였지만, shift함수를 이용 해버려서 배열의 데이터를 손상 시켰다. 이 부분은 아래와 같이 수정이 가능하다. function reduce ( arr , reducer , initValue ) { if ( !arr. length ) return initValue const [currentValue, ...others] = arr initValue = reducer( curren