2014-12-09 1 views
2

Редактировать: Поскольку я написал вопрос с неправильным примером и не описал свои проблемы, я сделаю это снова!Ruby Lazy Переменный 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) был бы остеклен (что не кажется очень совместимым, так как вызов карты (: to_i) «заставит» ее рассчитывать).

+1

Это может быть ошибка при реализации. – tadman

+1

@tadman: OP является 'flat_map'ping' Range', а не 'Enumerator :: Lazy'. Здесь просто нет лень, и вы не ожидали, что это произойдет. –

+1

Иисус, только заметил теперь отсутствующий #lazy звонок ... Мне нужно вернуться к моему неудачному примеру, чтобы увидеть, что было моей первой проблемой снова. – ChuckE

ответ

6

Вы на самом деле не используете ленивый перечислитель. Чтобы преобразовать нормальный перечислитель в ленивый, используйте метод Enumerable#lazy. Чтобы вернуть результаты, я бы рекомендовал использовать метод Enumerable::Lazy#force вместо to_a, потому что я думаю, что он показывает намерение более четко.

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