Skip to content

Instantly share code, notes, and snippets.

@bradmontgomery
Last active December 12, 2015 00:48
Show Gist options
  • Save bradmontgomery/4685762 to your computer and use it in GitHub Desktop.
Save bradmontgomery/4685762 to your computer and use it in GitHub Desktop.
class FListImmutableError(Exception):
def __init__(self, msg='Can\'t modify FList members'):
self.message = msg
def __str__(self):
return self.message
def f_tl(l):
return FList() if len(l) < 2 else l[1:]
def f_hd(l):
return l[0] if len(l) > 0 else FList()
class FList:
def __init__(self, l=[]):
if not type(l) == list:
l = [l]
self.internal = l
try:
self.check_list_type()
except TypeError, e:
print e.message
def __getitem__(self, key):
if type(key) == int or type(key) == slice:
try:
value = self.internal[key]
if type(key) == slice:
value = FList(value)
return value
except IndexError, e:
raise type(e)('index out of range')
else:
raise TypeError('argument must be integer or slice')
def __setitem__(self, key, value):
# lists are immutable!
raise FListImmutableError()
def __len__(self):
return len(self.internal)
def __repr__(self):
return 'FList(' + ', '.join(str(x) for x in self.internal) + ')'
def __add__(self, other):
return self.cons(other)
def hd(self):
return None if len(self) == 0 else self[0]
def tl(self):
return FList() if len(self) < 2 else self[1:]
def cons(self, l):
if not l.__class__ == FList:
l = FList(l)
t1 = self.get_list_type()
t2 = l.get_list_type()
if not (t1 is None or t2 is None or t1 == t2):
raise TypeError(
'attempting to join list of type %s with list of type %s'
% (t1, t2))
return FList(self.internal + l.internal)
def check_list_type(self):
if len(self) > 1:
compare = lambda x: type(x) == type(self.internal[0])
if not all(map(compare, self.internal)):
raise TypeError('item values must be of the same type')
def get_list_type(self):
return type(self[0]) if len(self) > 0 else None
from nose.tools import eq_, raises
from flist import FList, f_hd, f_tl, FListImmutableError
from random import randint
def _randchar(mixed_case=True):
letter = chr(randint(ord('a'), ord('z')))
if mixed_case and randint(0, 1) == 0:
letter = letter.upper()
return letter
def generate_password(l=FList(), z=12):
if len(l) == z:
return ''.join(l[:])
else:
return generate_password(l.cons(_randchar()), z)
def test_flist():
# create a new FList
l = FList(range(10))
# get an item
eq_(l[2], 2)
# get a slice
eq_(len(l[4:7]), 3)
eq_(l[4:7].__class__, FList) # Slices are FLists!
# head
eq_(l.hd(), 0)
# tail
eq_(len(l.tl()), 9)
# chaining
eq_(l.tl().tl().hd(), 2)
# nesting
eq_(f_hd(f_tl(f_tl(l))), 2)
# cons
eq_(
len(FList(list('good')).cons(FList(list('morning')))),
len(list('goodmorning'))
)
# recursion
eq_(len(generate_password()), 12)
# Exceptions
# ----------
@raises(FListImmutableError)
def test_immutable():
l = FList(range(10))
l[0] = 1069
@raises(IndexError)
def test_access_bounds():
l = FList([0])
l[5]
@raises(TypeError)
def test_homogeneous():
l = FList([1, 'a', True, None])
@raises(TypeError)
def test_homogeneous_cons():
FList(list('foo')).cons(FList(range(100)))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment