2017-12-12 12 views
1

Ramda 게으른

Ramda의 transduce에 대한이 creation of lazy sequences 수 있습니다. 많이 Ramda의 트랜스 듀서 : 게으른 일대 지점

R.chain

하나과 같이, 일대 연산자로서 트랜스 듀서 (REPL)를 사용할 수있다 :

const tapLog = R.tap((what) => console.log(what)) 

const suits = ['♠', '♥', '♦', '♣'] 
const ranks = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'J', 'Q', 'K', 'A'] 

const addRank = (suit) => R.map(concat(suit),ranks) 

var transducer = R.compose(
R.chain(addRank), 
tapLog, 
R.take(2) 
); 

R.into([], transducer, suits); 

// => ♠1 // console.log 
// => ♠2 // console.log 
// => ["♠1", "♠2"] 

문제

의 문제 위의 스 니펫은 R.map(concat(suit),ranks)이 게으르지 않을 것입니다 - 모든 순위가 매핑되어 (중간 배열 생성), 체인은 트랜스 듀서 시퀀스를 따라 하나씩 '파이프'합니다.

680k 그래프 노드를 매핑하지 않는 한 이것은 문제가되지 않습니다.

왜 이런 일이 발생합니까?

var chain = _curry2(_dispatchable(['fantasy-land/chain', 'chain'], _xchain, function chain(fn, monad) { 
if (typeof monad === 'function') { 
    return function(x) { return fn(monad(x))(x); }; 
} 
return _makeFlat(false)(map(fn, monad)); 
})); 

을 그리고 그것은 차단 어떤 게으른 평가 _makeFlat입니다 :

R.chain의 구현과 같이 보인다.

목표

게으른 일대 변환기 분기를 만들 수있는 방법이 있습니까?

R.reduce는 iterables을 지원합니다.

또한 해결책을 제공하지만 ramda를 사용하지 않는 related github issue을 참조하십시오.

답변

2

문제가 발생하면 R.map(concat(suit),ranks)이 발생하자마자 즉시 평가가됩니다. 이것은 기능과 관련이 없습니다. 변환기를 사용할 때 _dispatchable은 실제로 R.chain의 정의 내에서 함수 본문을 호출하지 않고 대신 _xchain 내부의 변환기 정의를 사용합니다.

전체 매핑 된 목록을 생성하는 대신, combineWith이라고하는 새 트랜스 듀서를 만들고 여기에 concat과 같은 기능을 사용하고 각 요소를 결합하여 목록을 작성하는 옵션이 있습니다. 변환. 길을 따라 @@transducer/reduced을 확인하면서 그렇게 할 수 있습니다.

const combineWith = (fn, xs) => xf => ({ 
 
    // proxy both `init` and `result` straight through 
 
    // see internal/_xfBase.js 
 
    '@@transducer/init': xf['@@transducer/init'].bind(xf), 
 
    '@@transducer/result': xf['@@transducer/result'].bind(xf), 
 

 
    // combine the item at each step with every element from `xs` 
 
    // using `fn`, returning early if `reduced` is ever encountered 
 
    '@@transducer/step': (acc, item) => { 
 
    for (const x of xs) { 
 
     acc = xf['@@transducer/step'](acc, fn(item, x)) 
 
     if (acc['@@transducer/reduced']) return acc 
 
    } 
 
    return acc 
 
    } 
 
}) 
 

 
const suits = ['♠', '♥', '♦', '♣'] 
 
const ranks = ['1', '2', '3', '4', '5', '6', '7', '8', '9', 'J', 'Q', 'K', 'A'] 
 

 
const tapLog = R.tap(console.log.bind(console, 'tapLog')) 
 

 
const transducer = R.compose(
 
    combineWith(R.concat, ranks), 
 
    tapLog, 
 
    R.take(2) 
 
) 
 

 
console.log('result', R.into([], transducer, suits))
<script src="//cdnjs.cloudflare.com/ajax/libs/ramda/0.25.0/ramda.min.js"></script>

+0

그래서 피 묻은 간단! 당신은 내 질문에 대답했을뿐만 아니라'R.transduce'에 대한 전체 문서를 완전히 demystified했습니다. 그리고 추측해라. .. [대답은 모두 함께 있었다] (https://github.com/ramda/ramda/blob/f494250c0aed9ecc096cc5b5b7823661edc14de2/source/internal/_xtap.js), 그것은 나를 속였던 모든 소음이다! init/result에 대해 자세히 설명하기 위해 약간 답을 수정했습니다. – Izhaki