2014-12-09 2 views
2

편집 : 잘못된 예제로 질문을 작성하고 내 문제를 설명하지 않았으므로 다시 할 것입니다.루비 게으른 열거 형 flat_map은 매우 게으른 게 아닙니다.

#flat_map은 Enumerator :: Lazy 클래스의 일부이지만 열거 할 수없는 항목입니다.

이 예는 제대로 작동합니다

(1..Float::INFINITY).flat_map { |s| [s,s] }.take(4).to_a 

게으른 구현은 작동합니다 : 블록 내에서 생성 된 배열이 한정되어 있음이 만 고려됩니다

(1..Float::INFINITY).flat_map { |s| [s,s] }.take(4).to_a 

. 그러나 take (4) 호출이 일어나기 전에 그들은 완전히 평가 될 것입니다. 그다지 유쾌하지는 않습니다. 따라서

이 실패합니다 :

(1..Float::INFINITY).lazy.flat_map { |i| (i..Float::INFINITY).map(&:to_i) }.take(4).force 

을 게으른 호출이 발생하기 전에 "배열에 무한대의 범위는"완벽하게 평가 될 것이기 때문에. 나는 그것이 "기본적으로 게으 르기"를 기대합니다. 내 말은, 난 수수께끼 거짓말을 이해하지만, 나는 이런 식으로 일어날 줄 알았는데 : flat_map 게으른 각 인스턴스를 평가하고, 그 결과가 배열 (또는 적어도 열거 가능)이 될 것이라는 것을 안다. 그리고 게으른 메커니즘을 적용 할 것이다. 그 위에. 따라서, (i..Float :: INFINITY) .map (& : to_i)은 lazified (매우 호환되지 않는 것 같아요.지도 (& : to_i) 호출은 계산을 "강제 실행"합니다).

+1

이것은 구현상의 버그 일 수 있습니다. – tadman

+1

@tadman : OP는 '열거 자 :: 지연'이 아닌'flat'map'Range'입니다. 여기에는 게으름이 없으며 그곳에있을 것으로 기대하지 않습니다. –

+1

예수님, 실종 된 #lazy 콜만을 발견했습니다 ... 나의 초기 문제가 무엇인지 다시 한 번 생각해보아야 할 것입니다. – ChuckE

답변

6

실제로는 게으른 열거자를 사용하지 않습니다. 일반 열거자를 게으른 것으로 변환하려면 Enumerable#lazy 메서드를 사용하십시오. 다시 결과를 얻으려면 to_a 대신 Enumerable::Lazy#force 메서드를 사용하는 것이 좋습니다. 의도를보다 명확하게 보여주기 때문입니다.

(1..Float::INFINITY).lazy.flat_map { |s| [s,s] }.take(4).force 
#=> [1, 1, 2, 2]