2009-10-05 4 views

Répondre

28

tableaux Ruby ne sont pas mises en œuvre sous forme de listes des liaisons simples liées, il est donc pas aussi utile d'avoir la voiture et cdr et d'autres choses.

Si vous vouliez vraiment, vous pourriez faire

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

Non seulement ce n'est pas utile, ce n'est pas vraiment significatif. Car, cdr et les inconvénients sont intrinsèquement liés à des cellules contre. Puisque par contre les cellules ne sont pas du tout impliquées dans les réseaux Ruby, une telle méthode serait un abus de langage. – Chuck

2

Je recommande la lecture de l'API Ruby pour Array. Il existe de nombreuses méthodes et opérateurs qui peuvent faire exactement ce dont vous avez besoin.

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

+0

Bien qu'il soit possible d'obtenir le 'cdr' pour un tableau de diverses manières, y compris' aire [1 ..- 1] ', ce n'est pas tout à fait le même à mon humble avis comme ayant une méthode qui fait exactement ce qui est nécessaire. – Phrogz

+0

Ce qui est pourquoi Ruby a ce merveilleux pour définir les méthodes qui font exactement ce dont vous avez besoin: 'la classe Array; def cdr; soi [1 ..- 1]; fin; fin – SFEley

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

Bien sûr, comme vous le savez, ce ne sont pas trop près de Lisp. Le véritable équivalent de rubis serait quelque chose comme [1, [2, [3, nil]]]. Vous pouvez toujours écrire une classe List ... ou en trouver un quelque part.

Le chapitre 8 de Practical Ruby Projects est appelé Implémentation de Lisp dans Ruby.

10

Voici comment vous souhaitez mettre en œuvre des listes simples liés Lisp en rubis:

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

Nice ........... – DigitalRoss

7

semi-sérieux, si vous voulez CONS, CAR et le CDR en Ruby, vous pourriez faire pire 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 

Et vous pouvez définir vos procédures de liste,

 
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 

Et vous pourriez obtenir la somme des carrés impairs uares dans la plage de 1 à 10:

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

Non, mais il est assez facile d'écrire le vôtre si nécessaire.

Questions connexes