Enumerator와 Enumerator:Lazy의 차이

7401 단어 Ruby

개시하다


Ruby2.0은 Enumerable#lazy 방법과 반환 값Enumerator::Lazy을 가져왔다.
이 글은 Enumerable#lazyEnumerator::Lazy가 무한 목록의 맵을 소개했다.
또 설명EnumeratorEnumerator::Lazy의 본질적 차이도 설명했다.

지연 목록


지연 목록은 Haskell 등 일부 함수형 언어에서 자주 사용하는 것이다
지연평가란 값이 필요하기 전에 계산하지 않으면 무한 연장된 목록을 처리할 수 있다는 것이다.

무한 목록 추가


그냥 해보면 안 돼요.


다음은 무한 목록Range의 표현식[1]이다.
이 공식의 집행은 끝나지 않는다.
무한 목록 맵을 실행하면 끝나지 않습니다
[1] pry(main)> (1..Float::INFINITY).map{|n| n*2}.first(5)
# => (実行が終わらない...)
[1]의 공식map에서 map라고 부른다.Enumerable#map는 수조Enumerable#map를 반환값으로 하는 방법이기 때문에 무한 길이의 수조를 만들어야 처리가 끝나지 않는다.

레이지 붙이면 움직여요.


사용Array, 아래 방정식[2]과 같이 Enumerable#lazy를 통해 무한 목록을 처리할 수 있다.
무한 목록은 Enumerable#lazy에서 처리할 수 있습니다.
[2] pry(main)> (1..Float::INFINITY).lazy.map{|n| n*2}.first(5)
# => [2, 4, 6, 8, 10]
[2]의 공식map에서 map라고 부른다.Enumerator::Lazy#map는 목록(Aray, Range 등)을 지연 목록Enumerable#lazy으로 전환하는 방법이다.Enumerator::Lazy도 되돌아오는 방법Enumerator::Lazy#map이다.
따라서 Enumerator::Lazy 전체는(1..Float::INFINITY).lazy.map{|n| n*2}이다.Enumerator::Lazy의 내용은 호출Enumerator::Lazy 또는force(to_a) 이전에 수치를 평가하지 않는다.
마지막으로 first라고 불렸을 때 드디어 수치를 평가해야 하기 때문에 무한 목록을 처리할 수 있다.

게임 이름: Lazy#map


여기서 주의해야 할 것은 [1]과[2]의Enumerator::Lazy#first는 완전히 다른 방법으로 정의된 장소와 반환값이 모두 다르다는 것이다.
특히 [2]에서는 결과를 바로 배열하지 않고 지연 목록으로 저장하는 것이 중요하다.
  • [1]의 맵: map->Enumerable#map
  • [2]의 맵: Array->Enumerator::Lazy#map
  • 지연 시간 목록


    Ruby2.0부터 새로운 지연 명단이 나왔다고 오해할 수 있지만 이전부터 루비Enumerator::Lazy반이 있었다.
    예를 들어 Enumerator 블록을 생략하면 순서대로 IO#each_line 파일의 행별로 yield 반환됩니다.
    다음 예에서는 전체 파일을 읽지 않고 처음 열 줄만 처리할 수 있습니다.
    IO#each_line에서 모든 파일을 읽지 않습니다.
    File.open("log.txt") do |f|
      puts f.each_line.first(10)
    end
    
    놀랍게도 EnumeratorEnumerator::Lazy는 모두 지연 목록이었다.
    조금만 신경 쓰면Enumerator무한 리스트를 처리할 수도 있다.이것은 첫 번째 예의 결과와 완전히 같다.
    Enumerator는 무한 목록을 처리할 수도 있습니다.
    Enumerator.new{|y|
      (1..Float::INFINITY).each{|n|
        y << n*2
      }
    }.first(5) # => [2, 4, 6, 8, 10]
    
    이렇게 해서 Enumerator 무한 목록을 처리할 수도 있지만 Enumerator를 사용하면
    맵을 통해 직관적이고 읽기 쉬운 짧은 코드로 표현할 수 있다.

    란즈의 진정한 목적

    Enumerator::LazyEnumerator::Lazy 두 종류의 본질적인 차이는 다음과 같다.
    방법체인에서 호출Enumerator이 되돌아오는지map 또는 되돌아오는지Array.
    두 학급 자체의 기능은 거의 차이가 없다.
    다시 말하면 Enumerator::Lazy의 진정한 목적은 레이지판Enumerator::Lazymap를 새롭게 정의하는 것이다.

    lazy를 더하면 맵의 동작이 변하는 불가사의한 방법


    왜, lazy를 더하면 맵과 select의 동작이 달라질까요?이런 의문이 생기는 사람도 있을 거라고 생각합니다.
    Enumerable#lazy를 제작한 Yutaka HARA씨가 알탄라고 대답했다.
  • select 모듈에서 레이지 버전을 원하는 방법Enumerable,map,select,reject,drop,...많이요.
  • 모듈을 모두 추가하면 Enumerable 모듈의 방법이 너무 많아집니다.
  • Enumerator::Lazy 명명 공간을 제공함으로써'lazy'의 방법 이름만 추가하면 lazy판mapselect 등을 사용할 수 있다.
  • 링크된 글에서도Enumerable#lazy "mapselect 등lazy판의 명명 공간을 제공하는 방법"을 설명한 것이 더 정확한 설명이다.

    총결산

  • 지연 목록을 통해 무한 목록 등을 간단하게 처리할 수 있다
  • Enumerator::LazyEnumerator의 본질적 차이점mapselect 등 방법의 행위가 다르다
  • Enumerator::Lazy의 진정한 목적은 레이지 버전의 mapselect
  • 를 재정의하는 것이다.

    보태다


    학급 계승 관계

    Enumerator::Lazy,Enumerator,Enumerable 등의 계승 관계가 복잡하기 때문에 그림으로 정리했다.

    딜레이 리스트를 사용할 수 있는 장면입니다.


    마지막으로 나는 지연 목록을 효과적으로 사용할 수 있는 장면을 생각했다.
  • 무한 길이의 수열을 수학적으로 처리하고 싶다
  • Twitter의 Time Line
  • 거대한 파일(일부만 처리)
  • 특히 수학 처리에 도움이 된다.mapfirst 방법을 사용하면 수열의 길이를 의식하지 않고 각 처리를 추상화할 수 있다.

    나는 블로그를 쓰고 있다.


    블로그에도 같은 내용의 기사를 썼다.

    좋은 웹페이지 즐겨찾기