Are there ruby equivalents to the lisp car, cdr, and cons functions? For those unfamiliar with lisp, here's what I want from ruby:
[1,2,3].car => 1
[1,2,3].cdr => [2,3]
[2,3].cons(1) => [1,2,3]
(in lisp):
(car '(1 2 3)) => 1
(cdr '(1 2 3)) => (2 3)
(cons 1 '(2 3)) => (1 2 3)
Ruby arrays are not implemented as singly-linked lists, so it is not as useful to have car and cdr and stuff.
If you really wanted, you could do
[1,2,3][0] => 1
[1,2,3].first => 1
[1,2,3][1..-1] => [2,3]
[1] + [2,3] => [1,2,3]
This is how you'd implement lisp-like single-linked lists in 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))
Semi-seriously, if you want CONS, CAR, and CDR in Ruby, you could do worse than
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
And then you can define your list procedures,
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
And then you might get the sum of the odd squares in the range 1 to 10:
reduce(lambda {|x, y| x + y},
0,
filter(lambda {|x| x % 2 == 1},
map(lambda {|x| x * x},
interval(1, 10))))
=> 165
>> [1,2,3].drop 1
=> [2, 3]
>> [1,2,3].first
=> 1
Of course, as you know, these aren't too close to Lisp. The real ruby equivalent would be something like [1, [2, [3, nil]]]
. You could always write a List class...or find one somewhere.
Chapter 8 of Practical Ruby Projects is called Implementing Lisp in Ruby.
I'd recommend reading the Ruby API for Array
. There are many methods and operators there that can do exactly what you need.
http://www.ruby-doc.org/core/classes/Array.html
No there isn't, but it is easy enough to write your own if needed.