Operator kompozycji w Rubim
Jako język funkcyjny Haskell posiada wiele ciekawych własności, m.in. umożliwia kompozycje funkcji. Tzn. możemy zdefiniować dwie funkcje a operator kompozycji przekształca je w trzecią funkcję, która jest złożeniem tychże.
Zastanawiałem się przez chwilę, czy coś takiego możliwe jest do zrobienia w Rubim. Jak wiadomo posiada on pewne cechy języków funkcyjnych, ale nie jest tak zaawansowany jak Haskell – w szczególności jest dynamicznie typizowany, więc nie umożliwia statycznej analizy typów. Niemniej jednak możliwość zdefiniowania operatora kompozycji wydała mi się interesującym wyzwaniem.
Okazuje się, że w Rubim można zrobić to dość łatwo – wystarczy rozszerzyć definicję klasy Proc
o operator powiedzmy
*
, który pozwalał będzie na składanie funkcji. Definicja tego operator wygląda następująco:
class Proc def *(other) ->(x){self[other[x]]} end end
Dzięki tak zdefiniowanemu operatorowi możliwe jest składanie funkcji:
f = ->(x){x + 1} g = ->(x){x * 2} f[g[1]] #=> 24 - zwykłe złożenie (f * g)[1] #=> 24 - złożenie z użyciem operatora)
Co więcej, okazuje się, że w Rubim dość łatwo można składać funkcje więcej niż 1-argumentowe (w Haskellu nie ma takiej możliwości – konieczne jest jawne użycie krotek (tuple); w praktyce sprowadza się to do składania funkcji jednoargumentowcych). Odpowiednia definicja wygląda następująco:
class Proc def *(other) ->(*args){self[*other[*args]]} end end f = ->(x,y){[x + y,x - y]} g = ->(x,y){[x * y,x / y]} (f * g)[10,2] #=> [25,15]
Oczywiście w Rubim też w zasadzie budujemy krotki, ale nie zmienia to faktu, że funkcje f i g w tym przykładzie są dwuargumentowe.
Podsumowując – powyższe przykłady pokazują, że w Rubim można dość łatwo uzyskać niektóre interesujące cechy programowania funkcyjnego.