Ruby: předání bloku do lambdy / Proc (tam je yield) - LocalJumpError no block gi

Zdravím do programátorského koutku, přidám se něco z Ruby. Je to problém, zda je možné nějak ohnout bloky a yield naruby , případě jak dostat blok do vnitřního bloku(proc).

Mám takový to příklad (důležité je, že proměnná generator je daná a že je to typ Proc nebo Lambda.)
Kód: [Vybrat]
generator = proc {a,b=0,1 ; while(true) do a,b=b,a+b ; yield ; break if b>120 ; end}
generator.call{|v|p v}
LocalJumpError: no block given (yield)
from (irb):3019:in `block in irb_binding'
from (irb):3018:in `call'
from (irb):3018


Jak předám blok (například {|res|puts res}, aby výsledek bylo vypsané 1\n2\n3,5,8...) tomuto Proc generator? Vím, že bloky jsou dělané na metody původně.

Samozřejmě to jde triviálně opravit(že předám blok jako argument, například pomocí &). Ale já právě chci zachovat původní formát
Kód: [Vybrat]
generator = proc {|&c|a,b=0,1 ; while(true) do a,b=b,a+b ; c.( b) ; break if b>120 ; end}
generator.call{|v|p v}


(v ruby pro Proc objekty jsou  , prc.call a prc.yield , prc.() synonyma, a začíná v tom trochu bordel: .yield metody je něco jiného než yield klíčové slovo a  prc() je chyba narozdíl od prc.() )


Pod čarou:
Inspirace vychází z konstrukce objektu Enumerator.new() (srozumitelnější pod pojmem Iterátor možná), který v konstruktoru přijímá blok (s argumentem Enumerator::Yielder, přes který vrací hodnoty). Tělo bloku (Enumerator::Generator) je generující funkce. A aby Enumerátor fungoval, tělo funkce hodnoty vracet přes  Enumerator::Yielder pomocí metody .<< (alias .yield, jde ale o třetí odlišnou yield konstrukci!)

Kód: [Vybrat]
it=Enumerator.new{|ýíldr| a=0 ; loop do a+=1 ; ýíldr << a ; end}
it.next , it.take(40), it.first ...

# Proč to nejde takto?  Resp. jak to udělat
it=Enumerator.new{ a=0 ; loop do a+=1 ; yield a ; end}


# Ono i když generátor si deklaruji jako funkci (nikoli proc), tak i tak je s tím dost ohýbání

def gen() ;  a=1; loop { a+=10 ; yield a ; sleep 0.1  } end
e=Enumerator.new {|yi|gen {|w|yi<<w}  }.take(8)


def Enum_method(m) ;  return Enumerator.new{|y|method(m).call{|v|y<<v}} end
Enum_method(:gen).take(4)


Zkoušeno:


gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
blok je lexikálně scopovaný, jestli proc vytváříte uvnitř funkce, použije se blok předaný funkci. Přes call to asi nejde, jestli to nějak jde, také bych to rád věděl.


K čemu to chcete používat moc nechápu.

Kód: [Vybrat]
it=Enumerator.new{ a=0 ; loop do a+=1 ; yield a ; end}

kde chcete předávat blok?

Citace
Kde předávat  blok
To je narážka na to, že uvnitř bloku je yield a tedy že nějak by se do výrazu musel přidat další blok(aby ho mohl volat), ale to možné(syntaxe dovoluje jeden blok) není?

myslel jsem obecnou konstrukci
Kód: [Vybrat]
Libovolna_funkce_co_vrati_hotový_Enumerator(){ a=0 ; loop do a+=1 ; yield a ; end}
#případně
tmp=lambda{ a=0 ; loop do a+=1 ; yield a ; end}
Libovolna_funkce_co__vrati_hotovy_Enumerator(tmp)

gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
vy chcete použít yield jako Yielder yield? To podle mě nejde, yield je klíčové slovo a chování je zadrátované natvrdo, zavolá blok. Nemůžete ani zavolat funkci, která se jmenuje yield. Jestli jde nějak dynamicky nastavit blok, nebo nějak jinak předat blok do proc v čase volání, rád bych věděl jak.

už o tom rozjímám několik dní
Blok samozřejmě předat jde
Kód: [Vybrat]
def funkce(proc-v-promenne, &blok-jako-promenna)
 yield # blok-jako-prom hned zavolá, nelze ho uložit
 blok-jako-promenna.call() #totéž jako výše, ale údajně  výkonnostně horší, neboť su musí vytvořit closure či co

 jinafunkce(blok-jako-promenna) # & z bloku vytvori proc
 jinafunkce(proc-v-promenne) # jde s nim pracovat stejne

  Proc.new # také vytvoří proc  z bloku za předaného funkci
funkce(){print 4}
Prostě ruby je magický a mám ho rád. Jen je vtipné, že se opakuje furt principle of least astonishment. Ono to platí, když chce člověk, programovat přirozeně , ale když chce zkoumat jak ruby funguje, je udiven...
Pokud tě zajímá čtení:
https://stackoverflow.com/questions/2306731/using-yield-inside-define-method-in-ruby (celé)
https://banisterfiend.wordpress.com/2010/11/06/behavior-of-yield-in-define_method/ - Zde bych chtěl polopaticky vysvětlit
Citace
That’s right, the yield in the define_method block is actually causing the hello method to close over the block passed to make_method.
a
Citace
Everyone knows that Ruby’s blocks close over local variables and constants but it appears they close over blocks too.
Asi pořádně nerozumím, co je closure(uzávěra) a tím spíš sloveso close(over)-"uzávěrovot"
« Poslední změna: 30. 08. 2019, 12:51:59 od Pivotal »


gill

  • ****
  • 270
    • Zobrazit profil
    • E-mail
Blok samozřejmě předat jde

implicitní blok do proc v čase volání podle mě jednoduše předat nejde. Jen v čase vytvoření.

Kód: [Vybrat]
def proc1
    proc {yield}
end

p1 = proc1 {puts "proc1 called"}
p1.call # "proc1 called"

ve starém Ruby bylo možné získat kód pomocí sourcify a znovu vyevalovat v jiném kontextu, ale sourcify v novém Ruby nefunguje, alternativy neznám

Nejjednodušší je používat explicitní blok