2009-10-05 10 views
20

¿Hay rubíes equivalentes a las funciones lisp car, cdr y cons? Para aquellos no familiarizados con Lisp, esto es lo que quiero de rubí:¿Hay equivalentes ruby ​​para automóvil, cdr y contras?

[1,2,3].car => 1 
[1,2,3].cdr => [2,3] 
[2,3].cons(1) => [1,2,3] 

(en Lisp):

(car '(1 2 3)) => 1 
(cdr '(1 2 3)) => (2 3) 
(cons 1 '(2 3)) => (1 2 3) 

Respuesta

28

matrices de Ruby no se implementan como listas simplemente enlazada, por lo que no es tan útil disponer de coche y CDR y esas cosas.

Si realmente quería, que podría hacer

[1,2,3][0]  => 1 
[1,2,3].first => 1 
[1,2,3][1..-1] => [2,3] 
[1] + [2,3]  => [1,2,3] 
+8

No solo no es útil, no es realmente significativo. Coche, CDR y contras están intrínsecamente vinculados a las células cons. Como las células cons no están involucradas en las matrices de Ruby, cualquier método de este tipo sería inapropiado. – Chuck

2

me gustaría recomendar la lectura de la API de Ruby para Array. Existen muchos métodos y operadores que pueden hacer exactamente lo que necesita.

http://www.ruby-doc.org/core/classes/Array.html

+0

Si bien es posible obtener 'cdr' para una matriz de varias maneras, incluyendo' ary [1 ..- 1] ', no es exactamente lo mismo en mi humilde opinión que tener un método que hace exactamente lo que se necesita. – Phrogz

+0

Por eso Ruby tiene esta maravillosa facilidad para definir métodos que hacen exactamente lo que necesita: 'clase Array; def cdr; self [1 ..- 1]; fin; end' – SFEley

4
>> [1,2,3].drop 1 
=> [2, 3] 
>> [1,2,3].first 
=> 1 

Por supuesto, como es sabido, estos no son demasiado cerca de Lisp. El equivalente real de ruby ​​sería algo así como [1, [2, [3, nil]]]. Siempre puedes escribir una clase List ... o encontrar una en algún lugar.

El capítulo 8 de Practical Ruby Projects se llama Implementando Lisp en Ruby.

10

Ésta es la forma en que le implementar listas simplemente enlazada Lisp en rubí:

class Object 
    def list? 
    false 
    end 
end 

class LispNilClass 
    include Enumerable 
    def each 
    end 

    def inspect 
    "lnil" 
    end 

    def cons(car) 
    Cell.new(car, self) 
    end 

    def list? 
    true 
    end 
end 

LispNil = LispNilClass.new 

class LispNilClass 
    private :initialize 
end 

class Cell 
    include Enumerable 

    attr_accessor :car, :cdr 

    def initialize(car, cdr) 
    @car = car 
    @cdr = cdr 
    end 

    def self.list(*elements) 
    if elements.empty? 
     LispNil 
    else 
     first, *rest = elements 
     Cell.new(first, list(*rest)) 
    end 
    end 

    def cons(new_car) 
    Cell.new(new_car, self) 
    end 

    def list? 
    cdr.list? 
    end 

    # Do not use this (or any Enumerable methods) on Cells that aren't lists 
    def each 
    yield car 
    cdr.each {|e| yield e} 
    end 

    def inspect 
    if list? 
     "(#{ to_a.join(", ") })" 
    else 
     "(#{car} . #{cdr})" 
    end 
    end 
end 

list = Cell.list(1, 2, 3) #=> (1, 2, 3) 
list.list? #=> true 
list.car #=> 1 
list.cdr #=> (2, 3) 
list.cdr.cdr.cdr #=> lnil 
list.cons(4) #=> (4, 1, 2, 3) 

notlist = Cell.new(1,2) #=> (1 . 2) 
notlist.list? #=> false 
notlist.car #=> 1 
notlist.cdr #=> 2 
notlist.cons(3) #=> (3 . (1 . 2)) 
+0

Agradable ........... – DigitalRoss

7

semi-serio, si quieres CONS, coche, y CDR en Ruby, usted podría hacer peor que

 
def cons(x,y) 
    return lambda {|m| m.call(x,y)} 
end 

def car(z) 
    z.call(lambda {|p,q| p}) 
end 

def cdr(z) 
    z.call(lambda {|p,q| q}) 
end 

Y a continuación, puede definir sus procedimientos de la lista,

 
def interval(low, high) 
    if (low > high) 
    return nil 
    else 
    return cons(low, interval(low + 1, high)) 
    end 
end 

def map(f, l) 
    if (l == nil) 
    return nil 
    else 
    cons(f.call(car(l)), map(f, cdr(l))) 
    end 
end 

def filter(p, l) 
    if (l == nil) 
    return nil 
    elsif (p.call(car(l))) 
    return cons(car(l), filter(p, cdr(l))) 
    else 
    return filter(p, cdr(l)) 
    end 
end 

def reduce(f, f0, l) 
    if (l == nil) 
    return f0 
    else 
    return f.call(car(l), reduce(f, f0, cdr(l))) 
    end 
end 

Y entonces es posible obtener la suma de los cuadrados extraña uares en el rango de 1 a 10:

 
reduce(lambda {|x, y| x + y}, 
     0, 
     filter(lambda {|x| x % 2 == 1}, 
       map(lambda {|x| x * x}, 
        interval(1, 10)))) 
=> 165 
-1

No, no es posible, pero es bastante fácil escribir el suyo si es necesario.

Cuestiones relacionadas