# Functional style linked-lists. (2.02)
# @see LcJ58j
from functools import reduce
# Pair.NIL constant.
class PairNilType:
def __bool__(self):
return False
def __iter__(self):
return; yield
def __repr__(self):
return '()'
class PairBaseProperties(type):
__nil = PairNilType()
@property
def NIL(cls):
return cls.__nil
class PairBase(metaclass=PairBaseProperties):
pass
# Pair.
class Pair(PairBase):
def __init__(self, first, rest=PairBase.NIL):
self.first = first
self.rest = rest
def __iter__(self):
while True:
yield self.first
self = self.rest
if not self:
break
def __repr__(self):
return '(' + ' '.join(map(str, self)) + ')'
def _append(tail, l):
assert l is Pair.NIL or isinstance(l, Pair), 'Pair expected!'
# @internal
# Copy and append elements.
while l:
tail.rest = Pair(l.first)
tail = tail.rest
l = l.rest
return tail
def _reverse(l):
# @internal
# Reverse a list (destructive).
prev = Pair.NIL
while l:
rest = l.rest
l.rest = prev
prev = l
l = rest
return prev
# Linked-list.
def pairs(*args):
# Elements to linked-list.
return pairs_from_iterable(args)
def pairs_from_iterable(a):
# Iterable to linked-list.
return _reverse(reduce(lambda init, x: Pair(x, init), a, Pair.NIL))
def appendl(ls):
# Append all lists.
temp = Pair(None)
foldl(lambda init, x: _append(init, x), temp, ls)
return temp.rest
def reversel(l):
# Reverse a list.
return foldl(lambda init, x: Pair(x, init), Pair.NIL, l)
def foldl(proc, init, l):
# Build result by applying a procedure to list elements.
return foldlp(lambda init, p: proc(init, p.first), init, l)
def foldlp(proc, init, l):
# Build result by applying a procedure to list pairs.
while l:
init = proc(init, l)
l = l.rest
return init
def foldrightl(proc, init, l):
# Build result by applying a procedure to list elements last to first.
return foldrightlp(lambda init, p: proc(init, p.first), init, l)
def foldrightlp(proc, init, l):
# Build result by applying a procedure to list pairs last to first.
return foldl(proc, init, foldlp(lambda init, p: Pair(p, init), Pair.NIL, l))
def mapl(proc, l):
# Map procedure over list elements; return list of results.
return maplp(lambda p: proc(p.first), l)
def maplp(proc, l):
# Map procedure over list pairs; return list of results.
return _reverse(foldlp(lambda init, p: Pair(proc(p), init), Pair.NIL, l))
def appendmapl(proc, l):
# Map procedure over list elements; return appended results.
return appendmaplp(lambda p: proc(p.first), l)
def appendmaplp(proc, l):
# Map procedure over list pairs; return appended results.
return appendl(maplp(proc, l))
def combinationsl(l, k):
# Generate ordered k-length combinations from list.
if k == 0:
return Pair(Pair.NIL)
return appendmaplp(lambda r: mapl(lambda c: Pair(r.first, c),
combinationsl(r.rest, k-1)), l)
# Test.
from itertools import combinations
n = 5
l = pairs_from_iterable(range(n))
l2 = pairs_from_iterable(range(n, n*2))
l3 = pairs_from_iterable('1234')
print(l)
print(list(l))
print(reversel(l))
print(mapl(lambda x: x**2, l))
print(appendl(pairs(Pair.NIL, l, Pair.NIL, l2, Pair.NIL)))
print(mapl(lambda x: Pair(x), l))
print(appendmapl(lambda x: Pair(x), l))
print(foldl(lambda x, y: '(' + x + '+' + y + ')', '0', l3))
print(foldrightl(lambda y, x: '(' + x + '+' + y + ')', '0', l3))
n = 4
a = range(1, 1+n)
l = pairs_from_iterable(a)
def reformat(ls):
return (tuple(x) for x in ls)
for k in range(1+n):
x = combinationsl(l, k)
y = list(reformat(x))
z = list(combinations(a, k))
print(x)
assert y == z, f'Mismatch for {n},{k}'
print('Okay.')
# Time.
from time import process_time
def _timeit(thunk):
try:
t = process_time()
thunk()
print('Elapsed: {:.6f}s'.format(process_time() - t))
except Exception as e:
print('Invalid:', e)
def make_f(n, k, count):
l = pairs_from_iterable(range(n))
def f():
for _ in range(count):
combinationsl(l, k)
return f
_timeit(make_f(8, 4, 400))
_timeit(make_f(16, 8, 1))
IyBGdW5jdGlvbmFsIHN0eWxlIGxpbmtlZC1saXN0cy4gKDIuMDIpCiMgQHNlZSBMY0o1OGoKCmZyb20gZnVuY3Rvb2xzIGltcG9ydCByZWR1Y2UKCiMgUGFpci5OSUwgY29uc3RhbnQuCgpjbGFzcyBQYWlyTmlsVHlwZToKICAgIGRlZiBfX2Jvb2xfXyhzZWxmKToKICAgICAgICByZXR1cm4gRmFsc2UKICAgIGRlZiBfX2l0ZXJfXyhzZWxmKToKICAgICAgICByZXR1cm47IHlpZWxkCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuICcoKScKCmNsYXNzIFBhaXJCYXNlUHJvcGVydGllcyh0eXBlKToKICAgIF9fbmlsID0gUGFpck5pbFR5cGUoKQogICAgQHByb3BlcnR5CiAgICBkZWYgTklMKGNscyk6CiAgICAgICAgcmV0dXJuIGNscy5fX25pbAoKY2xhc3MgUGFpckJhc2UobWV0YWNsYXNzPVBhaXJCYXNlUHJvcGVydGllcyk6CiAgICBwYXNzCgojIFBhaXIuCgpjbGFzcyBQYWlyKFBhaXJCYXNlKToKICAgIGRlZiBfX2luaXRfXyhzZWxmLCBmaXJzdCwgcmVzdD1QYWlyQmFzZS5OSUwpOgogICAgICAgIHNlbGYuZmlyc3QgPSBmaXJzdAogICAgICAgIHNlbGYucmVzdCA9IHJlc3QKCiAgICBkZWYgX19pdGVyX18oc2VsZik6CiAgICAgICAgd2hpbGUgVHJ1ZToKICAgICAgICAgICAgeWllbGQgc2VsZi5maXJzdAogICAgICAgICAgICBzZWxmID0gc2VsZi5yZXN0CiAgICAgICAgICAgIGlmIG5vdCBzZWxmOgogICAgICAgICAgICAgICAgYnJlYWsKCiAgICBkZWYgX19yZXByX18oc2VsZik6CiAgICAgICAgcmV0dXJuICcoJyArICcgJy5qb2luKG1hcChzdHIsIHNlbGYpKSArICcpJwoKZGVmIF9hcHBlbmQodGFpbCwgbCk6CiAgICBhc3NlcnQgbCBpcyBQYWlyLk5JTCBvciBpc2luc3RhbmNlKGwsIFBhaXIpLCAnUGFpciBleHBlY3RlZCEnCiAgICAjIEBpbnRlcm5hbAogICAgIyBDb3B5IGFuZCBhcHBlbmQgZWxlbWVudHMuCiAgICB3aGlsZSBsOgogICAgICAgIHRhaWwucmVzdCA9IFBhaXIobC5maXJzdCkKICAgICAgICB0YWlsID0gdGFpbC5yZXN0CiAgICAgICAgbCA9IGwucmVzdAogICAgcmV0dXJuIHRhaWwKCmRlZiBfcmV2ZXJzZShsKToKICAgICMgQGludGVybmFsCiAgICAjIFJldmVyc2UgYSBsaXN0IChkZXN0cnVjdGl2ZSkuCiAgICBwcmV2ID0gUGFpci5OSUwKICAgIHdoaWxlIGw6CiAgICAgICAgcmVzdCA9IGwucmVzdAogICAgICAgIGwucmVzdCA9IHByZXYKICAgICAgICBwcmV2ID0gbAogICAgICAgIGwgPSByZXN0CiAgICByZXR1cm4gcHJldgoKIyBMaW5rZWQtbGlzdC4KCmRlZiBwYWlycygqYXJncyk6CiAgICAjIEVsZW1lbnRzIHRvIGxpbmtlZC1saXN0LgogICAgcmV0dXJuIHBhaXJzX2Zyb21faXRlcmFibGUoYXJncykKCmRlZiBwYWlyc19mcm9tX2l0ZXJhYmxlKGEpOgogICAgIyBJdGVyYWJsZSB0byBsaW5rZWQtbGlzdC4KICAgIHJldHVybiBfcmV2ZXJzZShyZWR1Y2UobGFtYmRhIGluaXQsIHg6IFBhaXIoeCwgaW5pdCksIGEsIFBhaXIuTklMKSkKCmRlZiBhcHBlbmRsKGxzKToKICAgICMgQXBwZW5kIGFsbCBsaXN0cy4KICAgIHRlbXAgPSBQYWlyKE5vbmUpCiAgICBmb2xkbChsYW1iZGEgaW5pdCwgeDogX2FwcGVuZChpbml0LCB4KSwgdGVtcCwgbHMpCiAgICByZXR1cm4gdGVtcC5yZXN0CgpkZWYgcmV2ZXJzZWwobCk6CiAgICAjIFJldmVyc2UgYSBsaXN0LgogICAgcmV0dXJuIGZvbGRsKGxhbWJkYSBpbml0LCB4OiBQYWlyKHgsIGluaXQpLCBQYWlyLk5JTCwgbCkKCmRlZiBmb2xkbChwcm9jLCBpbml0LCBsKToKICAgICMgQnVpbGQgcmVzdWx0IGJ5IGFwcGx5aW5nIGEgcHJvY2VkdXJlIHRvIGxpc3QgZWxlbWVudHMuCiAgICByZXR1cm4gZm9sZGxwKGxhbWJkYSBpbml0LCBwOiBwcm9jKGluaXQsIHAuZmlyc3QpLCBpbml0LCBsKQoKZGVmIGZvbGRscChwcm9jLCBpbml0LCBsKToKICAgICMgQnVpbGQgcmVzdWx0IGJ5IGFwcGx5aW5nIGEgcHJvY2VkdXJlIHRvIGxpc3QgcGFpcnMuCiAgICB3aGlsZSBsOgogICAgICAgIGluaXQgPSBwcm9jKGluaXQsIGwpCiAgICAgICAgbCA9IGwucmVzdAogICAgcmV0dXJuIGluaXQKCmRlZiBmb2xkcmlnaHRsKHByb2MsIGluaXQsIGwpOgogICAgIyBCdWlsZCByZXN1bHQgYnkgYXBwbHlpbmcgYSBwcm9jZWR1cmUgdG8gbGlzdCBlbGVtZW50cyBsYXN0IHRvIGZpcnN0LgogICAgcmV0dXJuIGZvbGRyaWdodGxwKGxhbWJkYSBpbml0LCBwOiBwcm9jKGluaXQsIHAuZmlyc3QpLCBpbml0LCBsKQoKZGVmIGZvbGRyaWdodGxwKHByb2MsIGluaXQsIGwpOgogICAgIyBCdWlsZCByZXN1bHQgYnkgYXBwbHlpbmcgYSBwcm9jZWR1cmUgdG8gbGlzdCBwYWlycyBsYXN0IHRvIGZpcnN0LgogICAgcmV0dXJuIGZvbGRsKHByb2MsIGluaXQsIGZvbGRscChsYW1iZGEgaW5pdCwgcDogUGFpcihwLCBpbml0KSwgUGFpci5OSUwsIGwpKQoKZGVmIG1hcGwocHJvYywgbCk6CiAgICAjIE1hcCBwcm9jZWR1cmUgb3ZlciBsaXN0IGVsZW1lbnRzOyByZXR1cm4gbGlzdCBvZiByZXN1bHRzLgogICAgcmV0dXJuIG1hcGxwKGxhbWJkYSBwOiBwcm9jKHAuZmlyc3QpLCBsKQoKZGVmIG1hcGxwKHByb2MsIGwpOgogICAgIyBNYXAgcHJvY2VkdXJlIG92ZXIgbGlzdCBwYWlyczsgcmV0dXJuIGxpc3Qgb2YgcmVzdWx0cy4KICAgIHJldHVybiBfcmV2ZXJzZShmb2xkbHAobGFtYmRhIGluaXQsIHA6IFBhaXIocHJvYyhwKSwgaW5pdCksIFBhaXIuTklMLCBsKSkKCmRlZiBhcHBlbmRtYXBsKHByb2MsIGwpOgogICAgIyBNYXAgcHJvY2VkdXJlIG92ZXIgbGlzdCBlbGVtZW50czsgcmV0dXJuIGFwcGVuZGVkIHJlc3VsdHMuCiAgICByZXR1cm4gYXBwZW5kbWFwbHAobGFtYmRhIHA6IHByb2MocC5maXJzdCksIGwpCgpkZWYgYXBwZW5kbWFwbHAocHJvYywgbCk6CiAgICAjIE1hcCBwcm9jZWR1cmUgb3ZlciBsaXN0IHBhaXJzOyByZXR1cm4gYXBwZW5kZWQgcmVzdWx0cy4KICAgIHJldHVybiBhcHBlbmRsKG1hcGxwKHByb2MsIGwpKQoKZGVmIGNvbWJpbmF0aW9uc2wobCwgayk6CiAgICAjIEdlbmVyYXRlIG9yZGVyZWQgay1sZW5ndGggY29tYmluYXRpb25zIGZyb20gbGlzdC4KICAgIGlmIGsgPT0gMDoKICAgICAgICByZXR1cm4gUGFpcihQYWlyLk5JTCkKICAgIHJldHVybiBhcHBlbmRtYXBscChsYW1iZGEgcjogbWFwbChsYW1iZGEgYzogUGFpcihyLmZpcnN0LCBjKSwKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBjb21iaW5hdGlvbnNsKHIucmVzdCwgay0xKSksIGwpCgojIFRlc3QuCgpmcm9tIGl0ZXJ0b29scyBpbXBvcnQgY29tYmluYXRpb25zCgpuICA9IDUKbCAgPSBwYWlyc19mcm9tX2l0ZXJhYmxlKHJhbmdlKG4pKQpsMiA9IHBhaXJzX2Zyb21faXRlcmFibGUocmFuZ2UobiwgbioyKSkKbDMgPSBwYWlyc19mcm9tX2l0ZXJhYmxlKCcxMjM0JykKCnByaW50KGwpCnByaW50KGxpc3QobCkpCnByaW50KHJldmVyc2VsKGwpKQpwcmludChtYXBsKGxhbWJkYSB4OiB4KioyLCBsKSkKcHJpbnQoYXBwZW5kbChwYWlycyhQYWlyLk5JTCwgbCwgUGFpci5OSUwsIGwyLCBQYWlyLk5JTCkpKQpwcmludChtYXBsKGxhbWJkYSB4OiBQYWlyKHgpLCBsKSkKcHJpbnQoYXBwZW5kbWFwbChsYW1iZGEgeDogUGFpcih4KSwgbCkpCnByaW50KGZvbGRsKGxhbWJkYSB4LCB5OiAnKCcgKyB4ICsgJysnICsgeSArICcpJywgJzAnLCBsMykpCnByaW50KGZvbGRyaWdodGwobGFtYmRhIHksIHg6ICcoJyArIHggKyAnKycgKyB5ICsgJyknLCAnMCcsIGwzKSkKCm4gPSA0CmEgPSByYW5nZSgxLCAxK24pCmwgPSBwYWlyc19mcm9tX2l0ZXJhYmxlKGEpCgpkZWYgcmVmb3JtYXQobHMpOgogICAgcmV0dXJuICh0dXBsZSh4KSBmb3IgeCBpbiBscykKCmZvciBrIGluIHJhbmdlKDErbik6CiAgICB4ID0gY29tYmluYXRpb25zbChsLCBrKQogICAgeSA9IGxpc3QocmVmb3JtYXQoeCkpCiAgICB6ID0gbGlzdChjb21iaW5hdGlvbnMoYSwgaykpCiAgICBwcmludCh4KQogICAgYXNzZXJ0IHkgPT0geiwgZidNaXNtYXRjaCBmb3Ige259LHtrfScKcHJpbnQoJ09rYXkuJykKCiMgVGltZS4KCmZyb20gdGltZSBpbXBvcnQgcHJvY2Vzc190aW1lCgpkZWYgX3RpbWVpdCh0aHVuayk6CiAgICB0cnk6CiAgICAgICAgdCA9IHByb2Nlc3NfdGltZSgpCiAgICAgICAgdGh1bmsoKQogICAgICAgIHByaW50KCdFbGFwc2VkOiB7Oi42Zn1zJy5mb3JtYXQocHJvY2Vzc190aW1lKCkgLSB0KSkKICAgIGV4Y2VwdCBFeGNlcHRpb24gYXMgZToKICAgICAgICBwcmludCgnSW52YWxpZDonLCBlKQoKZGVmIG1ha2VfZihuLCBrLCBjb3VudCk6CiAgICBsID0gcGFpcnNfZnJvbV9pdGVyYWJsZShyYW5nZShuKSkKICAgIGRlZiBmKCk6CiAgICAgICAgZm9yIF8gaW4gcmFuZ2UoY291bnQpOgogICAgICAgICAgICBjb21iaW5hdGlvbnNsKGwsIGspCiAgICByZXR1cm4gZgoKX3RpbWVpdChtYWtlX2YoOCwgNCwgNDAwKSkKX3RpbWVpdChtYWtlX2YoMTYsIDgsIDEpKQ==