Queste funzioni “*”
(Strip from http://xkcd.com/)
Che cosa significa la “*
” in rember*
e insertR*
? In generale, data una funzione f, in programmazione funzionale f* significa applicare f uniformemente a una struttura. Se la struttura è una lista, f* restituisce una lista con tutti gli elementi trasformati da f. Se la struttura è un albero, il risultato sarà un albero.
Quindi la rember*
non è altro che la reject
applicata ad alberi (ovvero liste comunque innestate. Sì Ugo, alla fine queste liste sono piante :-).
Il prossimo passo è generalizzare: definire una funzione star
come fattor comune di insertR*
e rember*
, in modo da poter scrivere
def rember_star(a, l) star l, lambda { |sym| sym == a ? [] : [sym] } end def insertR_star(old, new, l) star l, lambda { |sym| sym == old ? [old, new] : [sym] } end
La funzione star
prende una lista e una funzione; dunque è una funzione di ordine superiore. Cool stuff! La mia soluzione:
def star(l, f) if l.is_a? Symbol l elsif l.empty? [] else f.call(star(l.first, f)) + star(l.rest, f) end end
Espresse così la rember*
e la insertR*
mi sembrano più chiare. La star
esprime lo schema ricorsivo, le lambda
descrivono cosa fare localmente.
Prossimo esercizio: risolvere in Ruby i problemi posti dal genio di Lists and Lists (Gordon Plotkin, 1996).
Vedi anche: Why Ruby is an acceptable LISP