함수형 프로그래밍에서 생성기 함수가 유효합니까?


17

질문은 :

  • 생성기는 기능적 프로그래밍 패러다임을 파괴합니까? 그 이유는 무엇?
  • 그렇다면 생성기를 기능 프로그래밍에 사용할 수 있습니까?

다음을 고려하세요:

function * downCounter(maxValue) {
  yield maxValue;
  yield * downCounter(maxValue > 0 ? maxValue - 1 : 0);
}

let counter = downCounter(26);
counter.next().value; // 26
counter.next().value; // 25
// ...etc

downCounter방법은 상태 비 저장으로 나타납니다. 또한 downCounter동일한 입력으로 호출 하면 항상 동일한 출력이 발생합니다. 그러나 동시에 전화next() 하면 일관된 결과가 생성되지 않습니다.

이 예제 counter에서는 생성기 객체이므로 생성자가 함수형 프로그래밍 패러다임을 깨뜨릴 지 여부가 확실하지 않으므로 호출 next()하면 정확히 동일한 생성기 객체와 동일한 결과가 생성됩니다 maxValue.

또한 someCollection[3]배열을 호출 하면 항상 네 번째 요소가 반환됩니다. next()마찬가지로 생성기 객체에서 네 번 호출 하면 항상 네 번째 요소가 반환됩니다.

더 많은 맥락을 위해 프로그래밍 카타 작업을하는 동안 이러한 질문이 제기되었습니다 . 질문에 대답 한 사람은 생성기가 함수형 프로그래밍에 사용될 수 있는지 여부와 상태를 유지하는지 여부에 대한 질문을 제기했습니다.


2
모든 프로그램은 상태를 유지합니다. 실제 질문은 그것이 기능 상태 로 자격이되는지, 그것이 "불변 상태"로 해석되고 일단 할당되면 변하지 않는 상태입니다. 각 호출에서 생성기가 다른 것을 반환하도록 할 수있는 유일한 방법은 변경 가능한 상태가 어떻게 든 관련되어 있다고 주장합니다.
Robert Harvey

답변:


14

발전기 기능은 특별히 특별하지 않습니다. 콜백 기반 스타일로 생성기 함수를 다시 작성하여 비슷한 메커니즘을 직접 구현할 수 있습니다.

function downCounter(maxValue) {
  return {
    "value": maxValue,
    "next": function () {
      return downCounter(maxValue > 0 ? maxValue - 1 : 0);
     },
  };
}

let counter = downCounter(26);
counter.value; //=> 26
counter.next().value; //=> 25

분명히, downCounter 그것이 얻는만큼 순수하고 기능적입니다. 여기에는 문제가 없습니다.

JavaScript가 사용하는 생성기 프로토콜에는 가변 객체가 포함됩니다. 필요하지 않습니다. 위 코드를 참조하십시오. 특히 변경 가능한 객체는 참조 투명성 을 잃어 버립니다 . 즉 표현식을 값으로 대체 할 수 있습니다. 내 예에서,하지만 counter.next().value것입니다 항상 로 평가 25한 시점에서이 -이 발생하고 얼마나 자주 우리가 그것을 반복 상관없이, 이것은 JS 발생기 경우가 아니라 26다음 25, 그것은 정말 모든 숫자가 될 수 있습니다. 생성기에 대한 참조를 다른 함수에 전달하면 문제가됩니다.

counter.next().value; //=> 25
otherFunction(counter); // does this consume the counter?
counter.next().value; // what will this be? It depends on the otherFunction()

따라서 발전기는 상태를 유지하므로 "순수한"기능 프로그래밍에 적합하지 않습니다. 다행스럽게도, 순수한 함수형 프로그래밍을 수행 할 필요는 없으며 실용적 일 수 있습니다. 생성기가 코드를 명확하게 만들면 양심이 나쁜 상태에서 사용해야합니다. 결국 JavaScript는 Haskell과 달리 순수한 기능 언어가 아닙니다.

그건 그렇고, Haskell에서는 게으른 평가를 사용하기 때문에 목록과 생성자를 반환하는 것에는 차이가 없습니다.

downCounter :: Int -> [Int]
downCounter maxValue =
  maxValue : (downCounter (max 0 (maxValue - 1)))
-- invoke as "take n (downCounter 26)" to display n elements
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.