Ruby ' s yield feature in relation to computer science

Niedawno odkryłem bloki Rubiego i jego funkcje i zastanawiałem się: gdzie to pasuje w teorii informatyki? Czy jest to technika programowania funkcyjnego, czy coś bardziej szczegółowego?

Author: hbw, 2009-04-18

4 answers

Ruby ' s yield nie jest iteratorem jak w C# i Pythonie. yield sama w sobie jest naprawdę prostą koncepcją, gdy zrozumiesz, jak działają bloki w Rubim.

Tak, bloki są funkcyjnymi funkcjami programowania, mimo że Ruby nie jest właściwie językiem funkcyjnym. W rzeczywistości Ruby używa metody lambda do tworzenia obiektów blokowych, która jest zapożyczona ze składni Lispu do tworzenia anonimowych funkcji - czym są bloki. Z punktu widzenia informatyki bloki Rubiego (i Lispa funkcje lambda) są zamknięciami . W języku Ruby metody zwykle zajmują tylko jeden blok. (Możesz przekazać więcej, ale jest to niezręczne.)

Słowo kluczowe yield w Rubim jest tylko sposobem wywołania bloku, który został podany metodzie. Te dwa przykłady są równoważne:

def with_log
  output = yield # We're calling our block here with yield
  puts "Returned value is #{output}"
end

def with_log(&stuff_to_do) # the & tells Ruby to convert into
                           # an object without calling lambda
  output = stuff_to_do.call # We're explicitly calling the block here
  puts "Returned value is #{output}"
end

W pierwszym przypadku, Zakładamy, że jest blok i mówimy, aby zadzwonić. W drugiej Ruby zawija blok w obiekt i przekazuje go jako argument. Pierwszy jest bardziej wydajny i czytelny, ale są właściwie to samo. Można by tak nazwać:

with_log do
  a = 5
  other_num = gets.to_i
  @my_var = a + other_num
end

I wyświetli wartość, która została przypisana do @my_var. (OK, więc to jest całkowicie głupia funkcja, ale myślę, że masz pomysł.)

Bloki są używane do wielu rzeczy w Ruby. Prawie w każdym miejscu, w którym używasz pętli w języku takim jak Java, jest ona zastępowana w Ruby metodami, które przyjmują bloki. Na przykład,

[1,2,3].each {|value| print value} # prints "123"
[1,2,3].map {|value| 2**value}    # returns [2, 4, 8]
[1,2,3].reject {|value| value % 2 == 0} # returns [1, 3]

Jak zauważył Andrew, jest również powszechnie używany do otwierania plików i wielu innych miejsca. Zasadniczo za każdym razem, gdy masz standardową funkcję, która może używać niestandardowej logiki (jak sortowanie tablicy lub przetwarzanie pliku), użyjesz bloku. Są też inne zastosowania, ale ta odpowiedź jest już tak długa, że obawiam się, że spowoduje zawały serca u czytelników ze słabszymi konstytucjami. Mam nadzieję, że to rozwiąże zamieszanie w tym temacie.

 104
Author: Chuck,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-04-22 02:41:54

Jest więcej do rzucania i blokowania niż zwykłe zapętlanie.

Seria wyliczanie liczby ma szereg rzeczy, które możesz zrobić z wyliczaniem, takich jak pytanie, czy oświadczenie jest prawdziwe dla każdego członka grupy, lub czy jest prawdziwe dla wszystkich członków, lub poszukiwanie któregokolwiek lub wszystkich członków spełniających pewien warunek.

Bloki są również przydatne dla zakresu zmiennej. Zamiast być wygodnym, może pomóc w dobrym projekcie. Na przykład kod

File.open("filename", "w") do |f|
  f.puts "text"
end

Zapewnia, że strumień plików jest zamknięty po zakończeniu, nawet jeśli wystąpi wyjątek, i że zmienna jest poza zakresem po zakończeniu.

Zwykły google nie wymyślił dobrego posta na blogu o blokach i plonach w Rubim. Nie wiem dlaczego.

Odpowiedź na komentarz :

Podejrzewam, że zostanie zamknięta z powodu zakończenia bloku, a nie dlatego, że zmienna wychodzi poza zakres.

Rozumiem, że nic specjalnego nie dzieje się, gdy ostatnia zmienna wskazująca na obiekt wychodzi poza zakres, poza tym, że obiekt ten kwalifikuje się do zbierania śmieci. Nie wiem, jak to potwierdzić.

Mogę pokazać, że obiekt file zostaje zamknięty, zanim zostanie pobrany śmieci, co zwykle nie dzieje się natychmiast. W poniższym przykładzie można zobaczyć, że obiekt file jest zamknięty w drugiej instrukcji puts, ale nie został pobrany.

g = nil
File.open("/dev/null") do |f|
  puts f.inspect # #<File:/dev/null>
  puts f.object_id # Some number like 70233884832420
  g = f
end
puts g.inspect # #<File:/dev/null (closed)>
puts g.object_id # The exact same number as the one printed out above,
  # indicating that g points to the exact same object that f pointed to
 6
Author: Andrew Grimm,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2012-11-29 01:44:03

Myślę, że yield wypowiedź pochodzi z językaCLU . Zawsze się zastanawiam, czy postać z Trona też była nazwana po CLU....

 2
Author: Daniel Lucraft,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-18 20:29:37

Myślę, że 'coroutine' jest słowem kluczowym, którego szukasz.

Np. http://en.wikipedia.org/wiki/Yield

Wydajność w informatyce i informatyce:

    W informatyce, punkt powrotu (i ponownego wejścia) koroutine
 0
Author: Brian,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-04-18 20:40:00