primitives.py implements a minimal subset of Scheme primitives. srfi_1.py implements a minimal subset of SRFI-1: List Library. * devscripts/scm/__init__.py: New file. * devscripts/scm/primitives.py: New file. * devscripts/scm/srfi_1.py: New file.
356 lines
9.5 KiB
Python
356 lines
9.5 KiB
Python
from __future__ import unicode_literals
|
|
|
|
from .primitives import *
|
|
|
|
|
|
"""
|
|
Module implemeting a minimal subset of SRFI-1: List Library
|
|
|
|
In Scheme:
|
|
append caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr
|
|
caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr cdaaar cdaadr
|
|
cdadar cdaddr cddaar cddadr cdddar cddddr concatenate drop-while every
|
|
filter first fold iota last length list list_ref lset-difference map reduce
|
|
reverse take-while
|
|
|
|
In Python:
|
|
append caar cadr cdar cddr caaar caadr cadar caddr cdaar cdadr cddar cdddr
|
|
caaaar caaadr caadar caaddr cadaar cadadr caddar cadddr cdaaar cdaadr
|
|
cdadar cdaddr cddaar cddadr cdddar cddddr concatenate drop_while every
|
|
filter first fold iota last length list list_ref lset_difference map reduce
|
|
reverse take_while
|
|
|
|
"""
|
|
|
|
# Use these procedures with caution,
|
|
# as too much car/cdr-ing may hinder readability
|
|
|
|
def caar(obj): return car(car(obj))
|
|
|
|
def cadr(obj): return car(cdr(obj))
|
|
|
|
def cdar(obj): return cdr(car(obj))
|
|
|
|
def cddr(obj): return cdr(cdr(obj))
|
|
|
|
def caaar(obj): return car(car(car(obj)))
|
|
|
|
def caadr(obj): return car(car(cdr(obj)))
|
|
|
|
def cadar(obj): return car(cdr(car(obj)))
|
|
|
|
def caddr(obj): return car(cdr(cdr(obj)))
|
|
|
|
def cdaar(obj): return cdr(car(car(obj)))
|
|
|
|
def cdadr(obj): return cdr(car(cdr(obj)))
|
|
|
|
def cddar(obj): return cdr(cdr(car(obj)))
|
|
|
|
def cdddr(obj): return cdr(cdr(cdr(obj)))
|
|
|
|
def caaaar(obj): return car(car(car(car(obj))))
|
|
|
|
def caaadr(obj): return car(car(car(cdr(obj))))
|
|
|
|
def caadar(obj): return car(car(cdr(car(obj))))
|
|
|
|
def caaddr(obj): return car(car(cdr(cdr(obj))))
|
|
|
|
def cadaar(obj): return car(cdr(car(car(obj))))
|
|
|
|
def cadadr(obj): return car(cdr(car(cdr(obj))))
|
|
|
|
def caddar(obj): return car(cdr(cdr(car(obj))))
|
|
|
|
def cadddr(obj): return car(cdr(cdr(cdr(obj))))
|
|
|
|
def cdaaar(obj): return cdr(car(car(car(obj))))
|
|
|
|
def cdaadr(obj): return cdr(car(car(cdr(obj))))
|
|
|
|
def cdadar(obj): return cdr(car(cdr(car(obj))))
|
|
|
|
def cdaddr(obj): return cdr(car(cdr(cdr(obj))))
|
|
|
|
def cddaar(obj): return cdr(cdr(car(car(obj))))
|
|
|
|
def cddadr(obj): return cdr(cdr(car(cdr(obj))))
|
|
|
|
def cdddar(obj): return cdr(cdr(cdr(car(obj))))
|
|
|
|
def cddddr(obj): return cdr(cdr(cdr(cdr(obj))))
|
|
|
|
def length(lst):
|
|
"""compute length of lst"""
|
|
def length_loop(lst, count):
|
|
if lst is nil:
|
|
return count
|
|
else:
|
|
return length_loop(cdr(lst),
|
|
count + 1)
|
|
return length_loop(lst, 0)
|
|
|
|
def list_ref(lst, k):
|
|
"""return the k^th element of lst"""
|
|
if k == 0:
|
|
return car(lst)
|
|
else:
|
|
return list_ref(cdr(lst), k - 1)
|
|
|
|
def iota(count):
|
|
"""return lst from 0 to (count - 1)"""
|
|
def iota_loop(loop_count):
|
|
if loop_count == count:
|
|
return nil
|
|
else:
|
|
return cons(loop_count,
|
|
iota_loop(loop_count + 1))
|
|
return iota_loop(0)
|
|
|
|
def _any(proc, arg_lst):
|
|
"""
|
|
any for procedures that take a single argument
|
|
|
|
Apply proc to every element in arg_lst
|
|
Return True is any of the result is True
|
|
Otherwise, return False
|
|
|
|
"""
|
|
if arg_lst is nil:
|
|
return False
|
|
elif proc(car(arg_lst)):
|
|
return True
|
|
else:
|
|
return _any(proc, cdr(arg_lst))
|
|
|
|
def _every(proc, arg_lst):
|
|
"""
|
|
every for procedures that take a single argument
|
|
|
|
Apply proc to every element in arg_lst
|
|
Return True is every result is True
|
|
Otherwise, return False
|
|
|
|
"""
|
|
if arg_lst is nil:
|
|
return True
|
|
elif not proc(car(arg_lst)):
|
|
return False
|
|
else:
|
|
return _every(proc, cdr(arg_lst))
|
|
|
|
def _map(proc, lst):
|
|
"""
|
|
map for procedures that take a single argument
|
|
|
|
Apply proc to every element in arg_lst and return the resulting lst
|
|
|
|
"""
|
|
if lst is nil:
|
|
return nil
|
|
else:
|
|
return cons(proc(car(lst)),
|
|
_map(proc, cdr(lst)))
|
|
|
|
def map(proc, *tuple_of_lst):
|
|
"""
|
|
map for procedures that take any number of arguments, including 1
|
|
|
|
Apply proc to the n^th element in lst from lst_of_lst
|
|
and return the resulting lst
|
|
|
|
"""
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
if _every(is_null, lst_of_lst):
|
|
return nil
|
|
elif _any(is_null, lst_of_lst):
|
|
raise IndexError("some of the lists are differed in length!")
|
|
else:
|
|
return cons(apply(proc,
|
|
_map(car, lst_of_lst)),
|
|
apply(map, cons(proc,
|
|
_map(cdr, lst_of_lst))))
|
|
|
|
def _fold(proc, init, lst):
|
|
"""
|
|
fold for procedures that take a single argument
|
|
|
|
If lst is the empty lst, return init
|
|
Otherwise, apply proc to the first element of lst and init in this order
|
|
Now, the result becomes the new init
|
|
|
|
"""
|
|
|
|
if lst is nil:
|
|
return init
|
|
else:
|
|
return _fold(proc, proc(car(lst), init), cdr(lst))
|
|
|
|
def reduce(proc, default, lst):
|
|
"""
|
|
If lst is the empty lst, return default
|
|
Otherwise, apply proc to the second element in lst
|
|
and the first element from lst in this order
|
|
Now, the result becomes the element after the remaining first element
|
|
|
|
"""
|
|
if lst is nil:
|
|
return default
|
|
elif cdr(lst) is nil:
|
|
return car(lst)
|
|
else:
|
|
return _fold(proc, car(lst), cdr(lst))
|
|
|
|
def any(proc, *tuple_of_lst):
|
|
"""
|
|
any for procedures that take any number of arguments, including 1
|
|
|
|
Apply proc to the n^th element in lst from lst_of_lst
|
|
Return True is any of the result is True
|
|
Otherwise, return False
|
|
|
|
"""
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
return reduce(lambda x, y: x or y,
|
|
False,
|
|
apply(_map, cons(proc,
|
|
lst_of_lst)))
|
|
|
|
def every(proc, *tuple_of_lst):
|
|
"""
|
|
every for procedures that take any number of arguments, including 1
|
|
|
|
Apply proc to the n^th element in lst from lst_of_lst
|
|
Return True is any of the result is True
|
|
Otherwise, return False
|
|
|
|
"""
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
return reduce(lambda x, y: x and y,
|
|
True,
|
|
apply(_map, cons(proc,
|
|
lst_of_lst)))
|
|
|
|
def reverse(lst):
|
|
"""reverse a given lst"""
|
|
return _fold(cons, nil, lst)
|
|
|
|
def filter(proc, lst):
|
|
"""
|
|
Apply proc to elements in lst
|
|
Remove those evaluated to False and return the resulting lst
|
|
|
|
"""
|
|
def filter_loop(proc, lst, accum):
|
|
if lst is nil:
|
|
return accum
|
|
elif proc(car(lst)):
|
|
return filter_loop(proc, cdr(lst), cons(car(lst), accum))
|
|
else:
|
|
return filter_loop(proc,
|
|
cdr(lst),
|
|
accum)
|
|
return reverse(filter_loop(proc, lst, nil))
|
|
|
|
def first(lst):
|
|
"""return the first element of lst, usually used with last"""
|
|
return car(lst)
|
|
|
|
def last(lst):
|
|
"""return the last element of lst, usually used with first"""
|
|
return car(reverse(lst))
|
|
|
|
def _append(lst1, lst2):
|
|
"""
|
|
append for procedure that takes a single argument
|
|
|
|
Append 2 lst into a single lst
|
|
|
|
"""
|
|
|
|
return _fold(cons, lst2, reverse(lst1))
|
|
|
|
def append(*tuple_of_lst):
|
|
"""
|
|
append for procedures that take any number of arguments, including 1
|
|
|
|
Append any number of lst into a single lst
|
|
|
|
"""
|
|
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
return reduce(_append, nil, reverse(lst_of_lst))
|
|
|
|
def concatenate(lst_of_lst):
|
|
"""concatenate lst_of_lst into a single lst"""
|
|
return apply(append, lst_of_lst)
|
|
|
|
def fold(proc, init, *tuple_of_lst):
|
|
"""
|
|
fold for procedures that take any number of arguments, including 1
|
|
|
|
If every element in lst_of_lst is the empty lst, return init
|
|
Otherwise, apply proc to the first element of every element in lst_of_lst
|
|
and init in this order
|
|
Now, the result becomes the new init
|
|
|
|
"""
|
|
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
if _every(is_null, lst_of_lst):
|
|
return init
|
|
elif _any(is_null, lst_of_lst):
|
|
raise IndexError("some of the lists are differed in length!")
|
|
else:
|
|
return apply(fold, cons(proc,
|
|
cons(apply(proc,
|
|
append(_map(car, lst_of_lst),
|
|
list(init))),
|
|
_map(cdr, lst_of_lst))))
|
|
|
|
def lset_difference(comparator, lst, *tuple_of_lst):
|
|
def _lset_difference(comparator, lst1, lst2):
|
|
"""treat lst1 and lst2 as sets and compute lst1 \ lst2"""
|
|
return filter(lambda x: _every(lambda y: not comparator(x, y),
|
|
lst2),
|
|
lst1)
|
|
lst_of_lst = tuple_to_lst(tuple_of_lst)
|
|
if lst_of_lst is nil:
|
|
return lst
|
|
else:
|
|
return apply(lset_difference,
|
|
cons(comparator,
|
|
cons(_lset_difference(comparator,
|
|
lst,
|
|
car(lst_of_lst)),
|
|
cdr(lst_of_lst))))
|
|
|
|
def drop_while(pred, lst):
|
|
"""
|
|
While predicate evaluates to True, drops the element
|
|
|
|
Return the lst if predicate evaluates to False or if lst is empty
|
|
|
|
"""
|
|
if lst is nil:
|
|
return nil
|
|
elif not pred(car(lst)):
|
|
return lst
|
|
else:
|
|
return drop_while(pred, cdr(lst))
|
|
|
|
def take_while(pred, lst):
|
|
"""
|
|
While predicate evaluates to True, takes the element
|
|
|
|
Return the empty lst if predicate evaluates to False or if lst is empty
|
|
|
|
"""
|
|
if lst is nil:
|
|
return nil
|
|
elif not pred(car(lst)):
|
|
return nil
|
|
else:
|
|
return cons(car(lst), take_while(pred, cdr(lst)))
|