Are there ruby equivalents to car, cdr, and cons?

前端 未结 5 934
终归单人心
终归单人心 2021-02-05 05:35

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]         


        
相关标签:
5条回答
  • 2021-02-05 06:14

    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
    
    0 讨论(0)
  • 2021-02-05 06:24

    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))
    
    0 讨论(0)
  • 2021-02-05 06:32

    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]
    
    0 讨论(0)
  • 2021-02-05 06:34
    >> [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.

    0 讨论(0)
  • 2021-02-05 06:34

    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

    0 讨论(0)
提交回复
热议问题