Proc#curry z kompletną listą argumentów

Trafiłem wczoraj na ciekawy przypadek: EventMachine udostępnia metodę add_timer, która oczekuje w bloku dostać kod callbacka. Niestety nie pozwala na przekazywanie dodatkowych argumentów do tego bloku, no ale w końcu to Ruby – można skorzystać z domknięcia. Potrzebowałem w pętli ustawić tych timerów całą masę, każdy z innymi parametrami i uznałem, że to idealne zastosowanie dla Proc#curry – dla każdego argumentu stworzę sobie proca z odpowiednim argumentem w domknięciu. Okazało się jednak, że #curry w Ruby ma pewną cechę – jeżeli zcurryowaną metodę wywoła się z ostatnim argumentem, to zostaje ona automatycznie wykonana i nie zwraca już proca…

Naprędce napisałem własne curry, które działa nieco inaczej:

def bcurry(f, *args) proc{|*nargs| f[*args, *nargs]} end
W ten sposób udało mi się problem rozwiązać, ale nie wydaje mi się to szczególnie zgrabne. Macie jakieś propozycje na rozwiązanie wykorzystujące metody biblioteczne? Czy ktoś potrafi wyjaśnić dlaczego oryginalne #curry zachowuje się tak a nie inaczej? Z pewnością to jest “fancy”, ale czy znajduje praktyczne zastosowania? :wink:

Oryginalnie tak się zachowuje ze względu że taka jest definicja partial application. Teoretycznie metoda której zaaplikowano ostatni argument powinna zostac wykonana. Ja bym to rozwiązał najbardziej lamerskim sposobem czyli dodał argument execute=nil na koniec metody i użył bibliotecznego curry :slight_smile:
W ten sposób po ostatnim “twoim” curry EM dostałby proca z jednym argumentem ‘execute’ którego wartość jest dowolna dla ciebie.

Hmm, ale ja nie wołam samodzielnie tej metody – robi to EM, więc jeżeli ona będzie przyjmować dwa argumenty to po zcurryowaniu i wywołaniu z pierwszym dostanę proca na którym bezargumentowy call zwróci kopię tego samego proca.

EDIT:

Z tego wynikało by, że #curry powinno działać dokładnie tak jak działa, a ja potrzebuję partial application właśnie, które nie jest chyba biblioteczne: http://en.wikipedia.org/wiki/Currying#Contrast_with_partial_function_application

Nie zrozumiałeś - różnica pomiiędzy partial application a currying jest tutaj niestotana. Obydwa sposoby standardowo po zaaplikoaniu ostatniego argumentu zwracają wartość nie funkcję bez argumentów.
Chodzi mi o to że chcesz dać callbacka: który zrobi puts x gdzie x to jest twoja wartość z pętli.

cos = lambda{|x,y,z| coś z tym robisz}.

10.times do |x|
add_timer soc.curry[x][y][z]
end

ale nie buja bo ostatni call zwraca wartość nie?

to robisz

cos = lambda{|x,y,z,execute| coś z tym zrobisz }

i nagle buja :slight_smile:

Z definicji, którą wziąłem z Wikipedii (wiem, że to nie jest jakieś fantastyczne źródło, ale zawsze) rozumiem, że papply zawsze zwraca funkcję tego samego rzędu, ale powiedzmy, że to nieistotne – tak czy siak nie ma bibliotecznego papply w Ruby.

[quote=Świstak]cos = lambda{|x,y,z,execute| coś z tym zrobisz }
i nagle buja[/quote]
Niestety nie buja. Napisałem to w poprzednim poście :slight_smile:

Problem z Twoją propozycją jest taki, że jeżeli zcurryowana lambda oczekuje jednego dodatkowego argumentu, to EM.timer wołając na niej bezargumentowy call zwróci identyczną kopię tego proca, oczejującą tego nieszczęsnego ostatniego argumentu – właśnie dlatego, że na oryginalnej lambdzie zawołałeś curry.

https://gist.github.com/1225596 może tak ?

Swoją drogą przydało by się coś podobnego dla ruby :slight_smile: http://benalman.com/news/2012/09/partial-application-in-javascript/

[quote=Paweł Kondzior]https://gist.github.com/1225596 może tak ?

Swoją drogą przydało by się coś podobnego dla ruby :slight_smile: http://benalman.com/news/2012/09/partial-application-in-javascript/[/quote]
Tzn. czego konkretnie brakuje?

Autoreklama:
http://apohllo.pl/blog/operator-kompozycji-w-rubim
http://apohllo.pl/blog/currying-w-rubim

[quote=apohllo][quote=Paweł Kondzior]https://gist.github.com/1225596 może tak ?

Swoją drogą przydało by się coś podobnego dla ruby :slight_smile: http://benalman.com/news/2012/09/partial-application-in-javascript/[/quote]
Tzn. czego konkretnie brakuje?

Autoreklama:
http://apohllo.pl/blog/operator-kompozycji-w-rubim
http://apohllo.pl/blog/currying-w-rubim[/quote]
Obecnie? Niczego, artykuł spadł z nieba dziś rano, wcześniej nie mogłem zabardzo znaleść nic ciekawego (w Ruby o partial application i curring)(zapewne kiepsko szukałem), można by zaprezentować implementacje w Ruby, ale po zapoznaniu się z materiałem to będzie zbyteczne :wink:

Chyba Cię po prostu źle zrozumiałem - myślałem, że chodzi Ci o jakieś funkcjonalności w Rubym, które są w JS, a Tobie, jak rozumiem, chodziło o artykuł :slight_smile: Tak czy siak, coś tam wyskrobałem - przydałoby się to jednak okrasić jakimiś bardziej życiowymi przykładami.

Dokładnie :slight_smile: Kolejna ciekawostka http://worrydream.com/AlligatorEggs/

O! Nowy paradygmat programowania - programowanie zorientowane kolorowo :wink:

https://bugs.ruby-lang.org/issues/6253

i ostatni komentarz https://bugs.ruby-lang.org/issues/6253#note-7

[quote]…
Proc#curry is like an easter egg. Matz felt no need to care about the
interaction between Proc#curry and other advanced features.
…[/quote]
To wiele tłumaczy :smiley: Ja w ciągle w szoku…

Dzięki za parę ciekawych linków!

Problem udało się rozwiązać poprzez zamianę pętli while na samodzielnie zdefiniowanego eacha – dzięki temu każda instancja proca zawierającego instrukcje dla schedulowanego timera miała własne domknięcie zawierające potrzebne dane. W tym wypadku curry czy partial application okazały się zbędne. Jak się nad tym dobrze zastanowić, to sytuacja, w której korzysta się z metod iterowania innych niż poprzez metodę przyjmującą blok należą do rzadkości, i praktycznie zawsze można ich uniknąć.

Takie podejście faktycznie sprawia, że curry i papply mogą być w świecie Ruby bardziej ciekawostkami niż niezbędnymi tworami.