2009-10-05 24 views
20

Có ruby ​​tương đương với các chức năng xe hơi, cdr và nhược điểm không? Đối với những người không quen với lisp, đây là những gì tôi muốn từ ruby:Có tương đương ruby ​​với ô tô, cdr và nhược điểm không?

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

(trong lisp):

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

Trả lời

28

mảng Ruby đang không được thực hiện danh sách như đơn lẻ liên kết, vì vậy nó không phải là hữu ích để có xe và cdr và các công cụ.

Nếu bạn thực sự muốn, bạn có thể làm

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

Không chỉ không hữu ích, nó không thực sự có ý nghĩa. Ô tô, cdr và khuyết điểm thực chất được liên kết với các tế bào khuyết điểm. Vì các ô khuyết điểm không liên quan đến mảng Ruby, nên mọi phương thức như vậy sẽ là một từ sai. – Chuck

2

tôi khuyên bạn nên đọc API Ruby cho Array. Có nhiều phương thức và toán tử có thể thực hiện chính xác những gì bạn cần.

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

+0

Mặc dù có thể lấy 'cdr' cho một mảng theo nhiều cách khác nhau, bao gồm' ary [1 ..- 1] ', đó không phải là IMHO giống như có phương thức thực hiện chính xác những gì cần thiết. – Phrogz

+0

Đó là lý do tại sao Ruby có cơ sở tuyệt vời này để xác định các phương thức thực hiện chính xác những gì bạn cần: 'class Array; def cdr; tự [1 ..- 1]; kết thúc; end' – SFEley

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

Tất nhiên, như bạn đã biết, đây không phải là quá gần với Lisp. Tương đương ruby ​​thực sẽ là một cái gì đó giống như [1, [2, [3, nil]]]. Bạn luôn có thể viết một lớp List ... hoặc tìm một nơi nào đó.

Chương 8 của Practical Ruby Projects được gọi là Triển khai Lisp trong Ruby.

10

Đây là cách bạn muốn thực hiện danh sách đơn liên kết lisp giống như trong ruby:

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

Đẹp ........... – DigitalRoss

7

Semi-nghiêm túc, nếu bạn muốn Nhược điểm, CAR và CDR trong Ruby, bạn có thể làm tồi tệ hơn

 
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 

Và sau đó bạn có thể định nghĩa thủ tục danh sách của bạn,

 
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 

Và sau đó bạn có thể nhận được tổng các vuông lẻ uares trong phạm vi từ 1 đến 10:

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

Không có, nhưng thật dễ dàng để viết của riêng bạn nếu cần.

Các vấn đề liên quan