2

컨테이너 유형 ([]/{})을 사용하지 않고 Javascript로 펑터를 구현하려고합니다. 따라서, 나는 전적으로 그들을 구성하는 순수 고차 기능을 활용 :펑터 또는 모나드는 각각 고차 함수로만 표현 될 수 있습니까?

const option = x => f => isAssigned(x) ? option(f(x)) : none; 
 

 
const none = option(null); 
 

 

 
const isAssigned = x => x !== null && x !== undefined; 
 
const inc = x => x + 1; 
 
const sqr = x => x * x; 
 
const head = xs => xs[0] 
 
const log = x => (console.log(x), x); 
 

 

 
option(head([4])) (inc) (sqr) (log); // 25 
 

 
option(head([])) (inc) (sqr) (log); // not executed

option는 값과 순수한 기능을한다 컨텍스트에 기능을 리프트, 값에 적용하고를 반환 같은 맥락에서 결과를 얻는다. 나는 그것이 functor라고 생각한다. 그러나 Javascript의 functor prototcol을 따르지 않으며 각 functor는 프로토 타입에 map 함수를 소유해야합니다.

option 분명히 (내 예를 하나처럼 동작 적어도) 모나드와 같은 형태로 확장 할 수 있습니다

const option = x => f => isAssigned(x) ? option(f(x)) : none; 
 

 
const option_ = x => f => isAssigned(x) ? flatten(option(f(x))) : none; 
 

 
const none = option(null); 
 

 
const of = x => option(x); // return 
 

 
const flatten = F => { // it gets a bit ugly here 
 
    let y; 
 

 
    F(z => (y = z, z)); 
 
    return y; 
 
}; 
 

 
// auxiliary functions 
 

 
const compn = (...fs) => x => fs.reduceRight((acc, f) => f(acc), x); 
 

 
const getOrElse = x => F => { 
 
    let y; 
 

 
    F(z => (y = z, z)); 
 
    return isAssigned(y) ? y : x; 
 
}; 
 

 
const isAssigned = x => x !== null && x !== undefined; 
 
const log = prefix => x => (console.log(prefix, x), x); 
 
const head = xs => xs[0]; 
 
const head_ = xs => option(xs[0]); 
 
const sqr = x => x * x; 
 

 
// some data 
 

 
const xs = [5], 
 
ys = []; 
 

 
// run 
 

 
const w = option(xs) (head), 
 
x = option(ys) (head), 
 
y = option_(xs) (head_), 
 
z = option_(ys) (head_); 
 

 
log("square head of xs:") (compn(sqr, getOrElse(1)) (w)); // 25 
 

 
log("square head of ys:") (compn(sqr, getOrElse(0)) (x)); // 0 
 

 
log("square head_ of xs:") (compn(sqr, getOrElse(0)) (y)); // 25 
 

 
log("square head_ of ys:") (compn(sqr, getOrElse(0)) (z)); // 0

option를 제공 실제로 내 질문은 펑터이다 : 문맥 적 (또는 효과적인) 계산의 결과가 호출 스택에 저장되는 (순수한) 상위 차수 함수만으로 모든 펑터/모나드를 표현할 수 있습니까?

+0

왜 이렇게할까요? "브라우저에서 haskell"이 당신의 목표라면 다른 솔루션이 있습니다 – niceman

+0

@ftor [교회 인코딩] (https://en.wikipedia.org/wiki/Church_encoding)과 같은 것을 의미합니까? – phg

+0

@phg 이론적 근거, 감사합니다. 이론적으로 가능합니다. Javascript로 구현할 실제 문제가 있는지 궁금해합니다. 지금까지'option'에는 (proto) 타입이 없습니다. 함수 ('of'와 같은)를 오른쪽 모나드와 어떻게 연관시킬 수 있습니까? 게다가,'option'은 단지 하나의 노동 조합입니다. 태그가없고 노동 조합이 채택한 가능한 유형을 반영 할 수단이 없습니다. – ftor

답변

1

물론. 함수는 모든 것을 거의 할 수 있습니다. 어쨌든, 당신은 당신 만 볼 수 아래 몇 JS 프리미티브에서 제외

( *, +, NumberString가) 기능을 보여^_^제공하기 위해 최선을 다해볼 게요 알 수 있도록 요청 :

  1. 변수
  2. 람다 추상화
  3. 응용 프로그램

그것은 공동 아니다 이러한 것들이 (본질적으로) λ- 계산법의 3 가지 기본 빌딩 블록이라는 것입니다.

const identity = x => x 
 
const fromNullable = x => x == null ? None : Option(x) 
 

 
const Option = (value) => k => { 
 
    const join =() => value 
 
    const map = f => Option(f(value)) 
 
    const bind = f => f(value) 
 
    const ap = m => optionMap(value)(m) 
 
    const fold = f => f(value) 
 
    return k (value, join, map, bind, ap, fold) 
 
} 
 

 
const None =() => k => { 
 
    const join = identity 
 
    const map = f => None() 
 
    const bind = f => None() 
 
    const ap = m => None() 
 
    const fold = f => f(null) 
 
    return k (null, join, map, bind, ap, fold) 
 
} 
 

 
const optionJoin = m => m((value, join, map, bind, ap, fold) => join()) 
 
const optionMap = f => m => m((value, join, map, bind, ap, fold) => map(f)) 
 
const optionBind = f => m => m((value, join, map, bind, ap, fold) => bind(f)) 
 
const optionAp = n => m => m((value, join, map, bind, ap, fold) => ap(n)) 
 
const optionFold = f => m => m((value, join, map, bind, ap, fold) => fold(f)) 
 

 
optionFold (console.log) (Option(5)) // 5 
 
optionFold (console.log) (None()) // null 
 

 
optionFold (console.log) (optionMap (x => x * 2) (Option(5))) // 10 
 
optionFold (console.log) (optionMap (x => x * 2) (None()))// null 
 

 
optionFold (console.log) (optionAp(Option(3)) (Option(x => x + 4))) // 7 
 
optionFold (console.log) (optionAp(Option(3)) (None())) // null 
 

 
optionFold (console.log) (optionBind(x => Option(x * x)) (Option(16))) // 256 
 
optionFold (console.log) (optionBind(x => Option(x * x)) (None())) // null 
 

 
optionFold (console.log) (optionJoin (Option(Option('hi')))) // 'hi' 
 
optionFold (console.log) (optionJoin (Option(None())))// null

+0

물론 관심이 있다면 토론을 기대합니다^_^ – naomik

+0

전체 API를'Option' 유형에 넣으십시오. 그건 의미가 있습니다. 나는 그걸 가지고 놀고 나중에 당신에게 돌아올거야. – ftor

+0

네, 그것을 치료하는 것은 일종의 클래스와 같습니다 - 편리하게 tho는 Option과 None 모두 자신의 "메소드"를 정의 할 수 있습니다 – naomik