Add a minimal scm module to provide Scheme-like data types and procedures.
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.
This commit is contained in:
parent
229ecdde27
commit
92f580152f
2
devscripts/scm/__init__.py
Normal file
2
devscripts/scm/__init__.py
Normal file
@ -0,0 +1,2 @@
|
|||||||
|
from .primitives import *
|
||||||
|
from .srfi_1 import *
|
196
devscripts/scm/primitives.py
Normal file
196
devscripts/scm/primitives.py
Normal file
@ -0,0 +1,196 @@
|
|||||||
|
from __future__ import unicode_literals
|
||||||
|
|
||||||
|
import re
|
||||||
|
import sys
|
||||||
|
|
||||||
|
|
||||||
|
"""
|
||||||
|
Module implemeting a minimal subset of Scheme primitives in term of Python
|
||||||
|
|
||||||
|
In Scheme:
|
||||||
|
apply car cdr cons display even? length list list->lst lst->list lst->tuple
|
||||||
|
list? null? object->string odd? pair? string? string->symbol symbol->string
|
||||||
|
symbol? tuple->lst
|
||||||
|
|
||||||
|
In Python:
|
||||||
|
apply car cdr cons display is_even length list list_to_lst lst_to_list
|
||||||
|
lst_to_tuple is_list is_null object_to_string is_odd is_pair is_string
|
||||||
|
string_to_symbol symbol_to_string is_symbol tuple_to_lst
|
||||||
|
|
||||||
|
"""
|
||||||
|
|
||||||
|
# standalone primitives
|
||||||
|
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
def display(obj): print(obj.encode("utf-8"))
|
||||||
|
else:
|
||||||
|
def display(obj): print(obj)
|
||||||
|
|
||||||
|
def is_even(x): return x % 2 == 0
|
||||||
|
|
||||||
|
def is_odd(x): return x % 2 != 0
|
||||||
|
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
is_string = lambda obj: isinstance(obj, (str, basestring))
|
||||||
|
else:
|
||||||
|
is_string = lambda obj: isinstance(obj, str)
|
||||||
|
|
||||||
|
if sys.version_info < (3, 0):
|
||||||
|
object_to_string = lambda obj: unicode(obj)
|
||||||
|
else:
|
||||||
|
object_to_string = lambda obj: str(obj)
|
||||||
|
|
||||||
|
# nil-related primitives
|
||||||
|
|
||||||
|
class _Nil:
|
||||||
|
"""internal class implementing the empty lst type"""
|
||||||
|
def __repr__(self): return "()"
|
||||||
|
|
||||||
|
def __str__(self): return "()"
|
||||||
|
|
||||||
|
# Many Scheme implementations don't have nil and use '() instead,
|
||||||
|
# but we can't do that as we don't know how to get quoting works in Python...
|
||||||
|
nil = _Nil()
|
||||||
|
|
||||||
|
def is_null(x): return x is nil
|
||||||
|
|
||||||
|
|
||||||
|
# pair/lst-related primitives
|
||||||
|
|
||||||
|
class _Pair:
|
||||||
|
"""internal class implementing the pair type"""
|
||||||
|
def __init__(self, car, cdr):
|
||||||
|
self.car = car
|
||||||
|
self.cdr = cdr
|
||||||
|
if cdr is nil or is_list(cdr):
|
||||||
|
self.is_list = True
|
||||||
|
else:
|
||||||
|
self.is_list = False
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""
|
||||||
|
Simulate representation of pair and list in Scheme REPL
|
||||||
|
|
||||||
|
In general, cons(x, y) is called a pair and is represented by (x . y)
|
||||||
|
|
||||||
|
However, if y is the empty lst, then cons(x, y) is called a lst
|
||||||
|
(avoid confusing with the procedure list,
|
||||||
|
treat list as a verb and lst as a noun)
|
||||||
|
and is represented by (x)
|
||||||
|
|
||||||
|
Moroever, if y is a lst and represented by (foo),
|
||||||
|
then cons(x,y) is also a lst and is represented by (x foo)
|
||||||
|
|
||||||
|
"""
|
||||||
|
pattern = r"^\(|\)$"
|
||||||
|
if self.cdr is nil:
|
||||||
|
return "(" + repr(self.car) + ")"
|
||||||
|
elif self.is_list:
|
||||||
|
return "(" + repr(self.car) + " " + \
|
||||||
|
re.sub(pattern, "", repr(self.cdr)) + ")"
|
||||||
|
else:
|
||||||
|
return "(" + repr(self.car) + " . " + repr(self.cdr) + ")"
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
"""
|
||||||
|
Same as __repr__.
|
||||||
|
|
||||||
|
Except repr(self.car) and repr(self.cdr) are replaced by
|
||||||
|
object_to_string(self.car) and object_to_string(self.cdr) respectively.
|
||||||
|
|
||||||
|
"""
|
||||||
|
pattern = r"^\(|\)$"
|
||||||
|
if self.is_list:
|
||||||
|
return "(" + object_to_string(self.car) + " " + \
|
||||||
|
re.sub(pattern, "", object_to_string(self.cdr)) + ")"
|
||||||
|
else:
|
||||||
|
return "(" + object_to_string(self.car) + " . " + \
|
||||||
|
object_to_string(self.cdr) + ")"
|
||||||
|
|
||||||
|
def __eq__(self, x):
|
||||||
|
return isinstance(x, _Pair) and self.car == x.car and self.cdr == x.cdr
|
||||||
|
|
||||||
|
def cons(a, b): return _Pair(a, b)
|
||||||
|
|
||||||
|
def car(pair): return pair.car
|
||||||
|
|
||||||
|
def cdr(pair): return pair.cdr
|
||||||
|
|
||||||
|
def is_pair(x): return isinstance(x, _Pair)
|
||||||
|
|
||||||
|
def is_list(x):
|
||||||
|
if x is nil:
|
||||||
|
return True
|
||||||
|
elif isinstance(x, _Pair):
|
||||||
|
return x.is_list
|
||||||
|
else:
|
||||||
|
return False
|
||||||
|
|
||||||
|
def list(*arg_tup):
|
||||||
|
"""build a lst from any number of elements"""
|
||||||
|
if arg_tup is ():
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
return cons(arg_tup[0], list(*arg_tup[1:]))
|
||||||
|
|
||||||
|
def tuple_to_lst(tup):
|
||||||
|
"""convert Python tuple to Scheme lst"""
|
||||||
|
if not tup:
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
return cons(tup[0], tuple_to_lst(tup[1:]))
|
||||||
|
|
||||||
|
def lst_to_tuple(lst):
|
||||||
|
"""convert Scheme lst to Python tuple"""
|
||||||
|
if lst is nil:
|
||||||
|
return ()
|
||||||
|
else:
|
||||||
|
return (lst.car,) + lst_to_tuple(lst.cdr)
|
||||||
|
|
||||||
|
def apply(proc, lst):
|
||||||
|
"""apply procedure proc to a Scheme lst"""
|
||||||
|
return proc(*lst_to_tuple(lst))
|
||||||
|
|
||||||
|
def list_to_lst(list_):
|
||||||
|
"""convert Python list to Scheme lst"""
|
||||||
|
if not list_:
|
||||||
|
return nil
|
||||||
|
else:
|
||||||
|
return cons(list_[0], list_to_lst(list_[1:]))
|
||||||
|
|
||||||
|
def lst_to_list(lst):
|
||||||
|
"""convert Scheme lst to Python list"""
|
||||||
|
if lst is nil:
|
||||||
|
return []
|
||||||
|
else:
|
||||||
|
return [lst.car,] + lst_to_list(lst.cdr)
|
||||||
|
|
||||||
|
|
||||||
|
# symbol-related primitives
|
||||||
|
|
||||||
|
# maintain a dictionary of symbol, to avoid duplication of _Symbol object
|
||||||
|
_symbol_dict = {}
|
||||||
|
|
||||||
|
class _Symbol:
|
||||||
|
"""internal class implementing the symbol type"""
|
||||||
|
def __init__(self, string):
|
||||||
|
self.string = string
|
||||||
|
_symbol_dict[string] = self
|
||||||
|
|
||||||
|
def __repr__(self):
|
||||||
|
"""remove leading and trailing quote from repr(self.string)"""
|
||||||
|
pattern = r"^'|^\"|\"$|'$"
|
||||||
|
return re.sub(pattern, "", repr(self.string))
|
||||||
|
|
||||||
|
def __str__(self):
|
||||||
|
return object_to_string(self.string)
|
||||||
|
|
||||||
|
def string_to_symbol(string):
|
||||||
|
"""convert Python string to Scheme symbol"""
|
||||||
|
if string not in _symbol_dict:
|
||||||
|
_symbol_dict[string] = _Symbol(string)
|
||||||
|
return _symbol_dict[string]
|
||||||
|
|
||||||
|
def symbol_to_string(symbol): return object_to_string(symbol)
|
||||||
|
|
||||||
|
def is_symbol(x): return isinstance(_Symbol)
|
355
devscripts/scm/srfi_1.py
Normal file
355
devscripts/scm/srfi_1.py
Normal file
@ -0,0 +1,355 @@
|
|||||||
|
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)))
|
Loading…
x
Reference in New Issue
Block a user