몬나드가 뭐라고 했어?(첫 부분)
19249 단어 monadfunctionaljavascript
Functor
과 Monad
같은 용어는 당신의 요점을 넘어섰을지도 모른다. "이 사람들이 도대체 무슨 말을 하는지 알고 싶다."이러한 이상한 이름과 더 많은 외국 해석이 대수(추상적인 유형)와 범주 이론을 깊이 이해해야 하기 때문에 이러한 유형의 구조가 우리의 편안한 일상 자바스크립트 코드에 어떻게 적합한지 알아보기 어려울 것이다.이 시리즈에서는 JavaScript 프로그래머의 관점에서 a
Monad
가 무엇인지, 그리고 일상 코드에서 어떻게 사용하는지 연구할 것이다.우리는 배후의 이론이 아니라 이런 유형의 용법에 주목할 것이다.예를 들어 다음과 같은 정의를 이해하려고 노력하는 것과 같다.
A
Monad
is aMonoid
in theCategory
ofEndofunctors
우리는 더욱 실용적인 정의를 이해하기 위해 노력할 것이다.
A
Monad
is a data type that allows for sequential application of its "effects" or "embellishments" while mapping its underlying data.
현재 두 번째 정의는 아직 명확하지 않겠지만, 나는 이 단어들이 어떻게 조합되어 왔는지 이해하기 위해 노력하는 것이 이해하기 쉽다고 생각한다.
우리가 자신의 유형을 만들기 위해 모험을 할 때, 첫 번째 정의를 이해하는 것이 중요하다.만약 당신과 내가 비슷한 점이 있다면, 나는 손을 더럽히는 것을 좋아하지만, 먼저 놀고, 그리고 그것을 어떻게 사용하는지에 대해 좋은 직감을 가지고 있을 때, 이론을 활용하여 이해를 쌓는 것을 좋아한다.일련의 유형이 이미 야외에서 이루어져서 우리는 즐겁게 놀 수 있다...그들의 배후의 수학을 모른다.
이 게시물들은 자바스크립트 언어뿐만 아니라 자바스크립트에서'currying','partial application','function composition'을 어떻게 실현하는지 이해해야 한다.만약 네가 이 화제들이 좀 모호하다고 생각한다면, 사이트에 너를 도와 정리할 수 있는 많은 자원이 있다.
따라서 더 많은 번거로움이 필요 없으니 해결을 시작합시다.
섹션 1: 대수 데이터 유형(ADT)
많은 사람들이'나는 이것
Monad
으로 이것을 하거나 그것Monad
으로 그것을 한다'고 말할 때 진정한 뜻은'나는 이 대수 데이터 형식(ADT)으로 이것, 저ADT로 저것을 한다'는 것이다.그들이 보여준 코드를 보면, 그들이 유형Monad
부분에 닿지 않았거나, 어떤 경우에는 유형이 심지어 그렇지 않은 경우Monad
를 발견할 수 있습니다.나는 먼저 나와 이 논쟁점을 해명하고 싶다.이것은 작은 일인 것 같지만, 우리가
Monad
와 데이터 유형에 대한 다른 방면의 초기 직각을 세우기 시작할 때, 우리가 진정 일부ADT를 가리킬 때, 사물을 aMonad
라고 부르는 것은 종종 혼동을 초래할 수 있다는 것을 나는 발견했다.대수 데이터 유형 a
Monad
가 도대체 어떤 구성인지 이해하기 전에 ADT가 무엇인지 알아야 한다.내가 생각할 수 있는 이 화제를 제기하는 가장 좋은 방법은ADT가 무엇인지에 대한 간단한 정의를 제공하는 것이다.그리고 자바스크립트의 ADT를 사용하여 더 익숙한 명령식 구현과 비교하는 방법을 보여 줍니다.다음 예제에서 처리할 데이터를 살펴보겠습니다.
// data :: [ * ]
const data = [
{ id: '9CYolEKK', learner: 'Molly' },
null,
{ id: 'gbdCC8Ui', learner: 'Thomas' },
undefined,
{ id: '1AceDkK_', learner: 'Lisa' },
{ id: 3, learner: 'Chad' },
{ gid: 11232, learner: 'Mitch' },
]
데이터는 혼합Array
으로 모든 종류의 값을 포함할 수 있다.이 특정한 실례에서 우리는 세 가지 유형이 있는데 그것이 바로 POJO
서로 다른 형태의 s(일반적인ol'JavaScript 대상), 하나Null
실례와 하나Undefined
실례이다.우리의 예제에서는 다음 요구 사항 목록을 사용하여 정의합니다.
Array
가 아니면 비어 있는 경우Object
로 돌아갑니다.Object
개의 유효 기록을 되돌려주고 유효id
키로 입력하여 모든 무효 기록을 효과적으로 필터합니다.Object
키가 있는 String
의id
로 정의합니다.Object
에 합리적인 기본값을 제공한다.Array
인지 확인하고 Object
으로 돌아갑니다.result
누적기를 설명하고 기본값을 비워 둡니다Object
.Array
및 각 항목에 대해 다음을 수행합니다.id
값을 입력합니다.안 그러면 아무것도 안 해.result
.// isArray :: a -> Boolean
const isArray =
Array.isArray
// isString :: a -> Boolean
const isString = x =>
typeof x === 'string'
// isObject :: a -> Boolean
const isObject = x =>
!!x && Object.prototype.toString.call(x) === '[object Object]'
// indexById :: [ * ] -> Object
function indexById(records) {
if (!isArray(records)) {
return {}
}
let result = {}
for (let i = 0; i < records.length; i++) {
const rec = records[i]
if (isObject(rec) && isString(rec.id)) {
result[rec.id] = rec
}
}
return result
}
indexById(null)
//=> {}
indexById([])
//=> {}
indexById([ 1, 2, 3 ])
//=> {}
indexById(data)
//=> {
// 9CYolEKK: { id: '9CYolEKK', learner: 'Molly' },
// gbdCC8Ui: { id: 'gbdCC8Ui', learner: 'Thomas' },
// 1AceDkK_: { id: '1AceDkK_', learner: 'Lisa' }
// }
보시다시피, 우리는 우리의 수요를 충족시키고, 우리가 제공한 모든 입력에 예상대로 응답할 수 있는 강력한 실현을 가지고 있습니다.우리의 ADT 실현에 대해 우리는
crocks
라이브러리에 매우 의존할 것이다.비록 JavaScript는 기능이 모두 갖추어진 프로그래밍 언어이지만, 이 언어들은 통용 언어가 아니라 엄격한 기능성 언어에 나타나는 구조가 부족하다.따라서 crocks
와 같은 라이브러리는 보통 ADT를 처리하는 데 쓰인다.다음은 ADT를 사용하여 요구 사항을 구현하는 것입니다.
const {
Assign, Maybe, composeK, converge, isArray,
isObject, isString, liftA2, mreduceMap, objOf,
prop, safe
} = require('crocks')
// wrapRecord :: Object -> Maybe Object
const wrapRecord = converge(
liftA2(objOf),
composeK(safe(isString), prop('id')),
Maybe.of
)
// mapRecord :: a -> Object
const mapRecord = record =>
safe(isObject, record)
.chain(wrapRecord)
.option({})
// indexById :: [ * ] -> Object
const indexById = records =>
safe(isArray, records)
.map(mreduceMap(Assign, mapRecord))
.option({})
indexById(null)
//=> {}
indexById([])
//=> {}
indexById([ 1, 2, 3 ])
//=> {}
indexById(data)
//=> {
// 9CYolEKK: { id: '9CYolEKK', learner: 'Molly' },
// gbdCC8Ui: { id: 'gbdCC8Ui', learner: 'Thomas' },
// 1AceDkK_: { id: '1AceDkK_', learner: 'Lisa' }
// }
나는 모두가 이 두 가지 실현 사이의 차이 중 하나가 ADT 실현에 익숙한 흐름 제어와 논리 모델이 부족하다는 것을 알아차리기를 바란다.두 번째 실현에서 for
순환과 if
문장은 한 번도 나타나지 않는다.그것들은 여전히 존재한다. 물론 존재하지만, ADT를 사용할 때, 우리는 이러한 흐름/논리를 특정한 유형으로 인코딩한다.예를 들어
safe
함수는 몇 곳에서 사용합니까?이 호출된 첫 번째 매개 변수에 전달되는 술어 함수를 봐라.여기서도 같은 검사를 했지만 if
함수가 아니라 safe
함수를 사용했습니다. 이 함수는 Maybe
라는 ADT를 되돌려줍니다.두 번째 실현 중 어느 곳에도 상태가 부족하다는 것을 알아차릴 수 있습니다.선언된 각 변수는 JavaScript 값이 아닌 함수입니다.최초의 실현에서, 우리는 두 개의 상태 비트
result
를 사용하여 최종 결과와 rec
라는 작은 조수를 조합했다. 이것은 코드를 정리하는 것일 뿐, Array
의 색인 값을 인용할 필요가 없다.함수
for
를 사용하여 모든 기록을 result
유형에 접으면 우리는 mreduceMap
순환과 Assign
변수의 수요에서 벗어날 수 있다.Assign
vanilla JavaScript에서 Object
와Object.assign
유사한 방식으로 추적result
Object
같은 누적기가 필요하지 않습니다.현재 우리는 누적된 방법이 생겨서 for
제거mreduceMap
순환에 의존할 수 있다.Maybe
,Assign
,접기 등은 이제 이해할 필요가 없다.내가 그것들을 언급한 것은 원시 실현 중의 모든 모델이 ADT 버전에 존재하고 여기에 마법이 없다는 것을 여러분에게 알려주고 싶었기 때문이다.ADT 인코딩을 사용할 때, 우리는 ADT에서 인코딩을 통해 축적, 논리, 흐름 제어, 상태 잡기 등 대량의 기계 위치를 제거하고, 유형이 모든 '파이프'를 처리하도록 합니다.내가 가장 듣기 싫은 것은 우리가 afluent api처럼 보이는 것을 어떻게 사용해서 우리의 조작을 함수
mapRecord
와 indexById
에 연결하는지 하는 것이다.이러한 코드를 보면 우리는 전형적인 대상 프로그래머가 사용할 수 있는 것처럼 전통적인Object
과 클래스를 사용하고 있다고 믿을 수 있다.방법이라고 불리는 이 조작 (모든 crocks 문서가 이렇게 되어 있음) 을 들었을 때, 그것은 심지어 강화되었다.이러한 직감적이고 오도적인 설명은 우리가 일상 코드에서 ADT를 사용하는 방식을 이해하는 데 방해가 될 수 있다.다음에 우리는 ADT의 사용을 더욱 깊이 연구하고 ADT가 어떻게
Object
s가 아닌지 탐색할 것이다. 왜냐하면 대상을 대상으로 하는 프로그래머가 볼 수 있기 때문이다Object
.오락성 단련
for
에서 사용할 수 있는 reduce
방법을 사용하여 첫 번째 POJ(순수ol'JavaScript) 함수를 가져오고 삭제Array.prototype
순환을 가져옵니다.result
변수에 무슨 일이 일어났는지, 그리고 {}
의 기본값이 어떻게 적용되는지 주의하십시오.setTimeout
나 setInterval
를 사용하지 않은 상태에서 당신이 생각할 수 있는 가장 낮은 효과의 실현으로 재구성한다.재구성할 때 가장 효과가 없다고 생각하는 것이 무엇인지 생각해 보세요.POJ
함수나 연습1의 재구성을 사용하여 그 자체 함수에 존재할 수 있는 이산 조작/변환을 확정한다.그리고 이 함수들을 만들고 주 함수를 재구성해서 사용하십시오.추가 단련(재미를 위해서)
// wrapRecord :: Object -> Maybe Object
const wrapRecord = converge(
liftA2(objOf),
composeK(safe(isString), prop('id')),
Maybe.of
)
// mapRecord :: a -> Object
const mapRecord = compose(
option({}),
chain(wrapRecord),
safe(isObject)
)
// indexById :: [ * ] -> Object
const indexById = records => compose(
option({ error: true }),
map(mreduceMap(Assign, mapRecord)),
safe(isArray),
)
Reference
이 문제에 관하여(몬나드가 뭐라고 했어?(첫 부분)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://dev.to/evilsoft/monad-say-what-part-1-4a61텍스트를 자유롭게 공유하거나 복사할 수 있습니다.하지만 이 문서의 URL은 참조 URL로 남겨 두십시오.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)