Lisp Mixin

This module provides Lisp-like functional notation. With this module it almost possible to write real Lisp code in Ruby.

Usage

It’s hardly believable, but the following IS valid ruby code:

  (def accumulate (fun, x, list)
    (if (null? list)
      x
    else
      (accumulate fun, (fun.call x, (car list)), (cdr list))
    end)
  end)

A real programmer can write LISP in any language ;)

Methods
Classes and Modules
Module Lisp::Format
Class Lisp::DottedPair
Public Class methods
format(format, *args)

Apply lisp format.

# File lib/facets/more/lisp_format.rb, line 46
  def self.format(format, *args)
    begin
      state = Format::State.new(args, Format::Output.new)
      formatter = Format::Formatter.new(format, state)
      formatter.run
    rescue => e
      puts 'Format error: ' + e.message
      puts format
      puts ' ' * (e.pos - 1) + '^' if e.respond_to? :pos
      raise
    end
  end
Public Instance methods
accumulate(fun, x, list)
This method is also aliased as foldleft
# File lib/facets/more/lisp.rb, line 280
  def accumulate(fun, x, list)
    if null?(list)
      x
    else
      accumulate(fun, fun.call(x, car(list)), cdr(list))
    end
  end
all?(pred, list)
# File lib/facets/more/lisp.rb, line 268
  def all?(pred, list)
    if null?(list)
      true
    else
      if pred.call(car(list))
        all?(pred, cdr(list))
      else
        false
      end
    end
  end
append(l, m)
# File lib/facets/more/lisp.rb, line 185
  def append(l, m)
    if null?(l)
      if null?(m)
        nil
      else
        cons(car(m), append(l, cdr(m)))
      end
    else
      cons(car(l), append(cdr(l), m))
    end
  end
assoc(x, list)
# File lib/facets/more/lisp.rb, line 251
  def assoc(x, list)
    f = filter(lambda { |y| x == car(y)}, list)
    if null?(f) then nil else car(f) end
  end
atom?(x)
# File lib/facets/more/lisp.rb, line 169
  def atom?(x)
    not pair?(x) || null?(x)
  end
car(pair)
# File lib/facets/more/lisp.rb, line 134
  def car(pair)
    pair = pair!(pair)
    pair.first
  end
cdr(pair)
# File lib/facets/more/lisp.rb, line 139
  def cdr(pair)
    pair = pair!(pair)
    pair.second
  end
cons(car, cdr)

Functional API

# File lib/facets/more/lisp.rb, line 126
  def cons(car, cdr)
    DottedPair.new(car, cdr)
  end
consonto(cdr, car)
# File lib/facets/more/lisp.rb, line 130
  def consonto(cdr, car)
    DottedPair.new(car, cdr)
  end
drop(l, n)
# File lib/facets/more/lisp.rb, line 332
  def drop(l, n)
    if n > 0 and not null?(l)
        drop(cdr(l), n - 1)
    else
        l
    end
  end
equal?(l, m)
# File lib/facets/more/lisp.rb, line 173
  def equal?(l, m)
    l == m
  end
exists?(pred, list)
# File lib/facets/more/lisp.rb, line 256
  def exists?(pred, list)
    if null?(list)
      false
    else
      if pred.call(car(list))
        true
      else
        exists?(pred, cdr(list))
      end
    end
  end
explode(string)
# File lib/facets/more/lisp.rb, line 304
  def explode(string)
    list(*(string.split(//)))
  end
filter(pred, list)
# File lib/facets/more/lisp.rb, line 239
  def filter(pred, list)
    if null?(list)
      nil
    else
      if pred.call(car(list))
        cons(car(list), filter(pred, cdr(list)))
      else
        filter(pred, cdr(list))
      end
    end
  end
foldleft(fun, x, list)

Alias for accumulate

foldright(fun, x, list)

Alias for reduce

format(format, *args)

See Lisp::format.

# File lib/facets/more/lisp_format.rb, line 61
  def format(format, *args)
    Lisp.format(format, *args)
  end
implode(list)
# File lib/facets/more/lisp.rb, line 308
  def implode(list)
    accumulate(lambda { |x, y| x + y }, '', list)
  end
length(list)
# File lib/facets/more/lisp.rb, line 197
  def length(list)
    if null?(list)
      0
    else
      1 + length(cdr(list))
    end
  end
link(lists)
# File lib/facets/more/lisp.rb, line 300
  def link(lists)
    accumulate(lambda { |x, y| append(x, y) }, nil, lists)
  end
list(*elms)
# File lib/facets/more/lisp.rb, line 177
  def list(*elms)
    if elms.empty?
      nil
    else
      cons(elms.shift, list(*elms))
    end
  end
map(fun, list)
# File lib/facets/more/lisp.rb, line 205
  def map(fun, list)
    if null?(list)
      nil
    else
      cons(fun.call(car(list)), map(fun, cdr(list)))
    end
  end
member?(x, list)
# File lib/facets/more/lisp.rb, line 227
  def member?(x, list)
    if null?(list)
      false
    else
      if x == car(list)
        true
      else
        member?(x, cdr(list))
      end
    end
  end
null?(x)
# File lib/facets/more/lisp.rb, line 156
  def null?(x)
    x == nil
  end
pair!(x)
# File lib/facets/more/lisp.rb, line 164
  def pair!(x)
    return x if pair?(x)
    return DottedPair[*x]
  end
pair?(x)
# File lib/facets/more/lisp.rb, line 160
  def pair?(x)
    x.is_a?(DottedPair)
  end
pairlis(l, m)
# File lib/facets/more/lisp.rb, line 223
  def pairlis(l, m)
    zip(lambda { |x, y| cons(x, y) }, l, m)
  end
prod(list)
# File lib/facets/more/lisp.rb, line 316
  def prod(list)
    accumulate(lambda { |x, y| x * y }, 1, list)
  end
reduce(fun, x, list)
This method is also aliased as foldright
# File lib/facets/more/lisp.rb, line 290
  def reduce(fun, x, list)
    if null?(list)
      x
    else
      fun.call(car(list), reduce(fun, x, cdr(list)))
    end
  end
reverse(lists)
# File lib/facets/more/lisp.rb, line 320
  def reverse(lists)
    accumulate(lambda { |x, y| consonto(x, y) }, nil, lists)
  end
set(var, val, binding)
# File lib/facets/more/lisp.rb, line 144
  def set(var, val, binding)
    eval "var = #{val}", binding
  end
set_car!(pair, val)
# File lib/facets/more/lisp.rb, line 148
  def set_car!(pair, val)
    pair.first = val
  end
set_cdr!(pair, val)
# File lib/facets/more/lisp.rb, line 152
  def set_cdr!(pair, val)
    pair.second = val
  end
sum(list)
# File lib/facets/more/lisp.rb, line 312
  def sum(list)
    accumulate(lambda { |x, y| x + y }, 0, list)
  end
take(l, n)
# File lib/facets/more/lisp.rb, line 324
  def take(l, n)
    if n > 0 and not null?(l)
      cons(car(l), take(cdr(l), n - 1))
    else
      nil
    end
  end
zip(fun, l, m)
# File lib/facets/more/lisp.rb, line 213
  def zip(fun, l, m)
    if null?(l) and null?(m)
      nil
    elsif null?(l) or null?(m)
      raise ArgumentError.new("zip with unequal length lists")
    else
      cons(fun.call(car(l), car(m)), zip(fun, cdr(l), cdr(m)))
    end
  end