Последний раз редактировалось _Ivana 16.06.2018, 01:17, всего редактировалось 1 раз.
Помните анекдот про Ежика? "Мужики, я вам изоленту принес!" (С) Впервые посидел с сабжем - настрогал кустарные бесконечные потоки с ленивыми вычислениями на них с кучей примеров - из второй главы того самого СИКПа про потоки, если надо - приведу остальные (интегрирование степенных рядов, вычисление Пи и т.п.). На лямбдах, один класс добавил - но он необязательный, одних лямбд было бы достаточно, только более громоздко писался бы код. Но даже на этих примерах очевидно, что все работает. С генераторами такая же ситуация - их еще проще реализовать на подобных абстракциях. Продолжаю не понимать зачем они в ядре языка
# волшебная троица
def cons(x, y): return (x,y)
def car(l): return l[0]
def cdr(l): return l[1]
# объект-обертка для мемоизированных ленивых вычислений
class Lazy:
def __init__(self, expr):
self.expression = expr
self.calculated = False
self.rezult = False
def getvalue(self):
if not self.calculated:
self.rezult = self.expression()
self.calculated = True
return self.rezult
# хвост потока
def stail(s):
t = cdr(s)
if callable(t):
return t()
elif isinstance(t, Lazy):
return t.getvalue()
else:
return t
# потоковые аналоги списковых функций
def stake(n, l):
r = []
while n>0:
r.append(car(l))
l = stail(l)
n = n-1
return r
def smap(f, s): return cons(f(car(s)), Lazy(lambda: smap(f, stail(s))))
def sfilter(f, s):
if f(car(s)):
return cons(car(s), Lazy(lambda: sfilter(f, stail(s))))
else:
return sfilter(f, stail(s))
def szipwith(f, a, b):
return cons(f(car(a), car(b)), Lazy(lambda: szipwith(f, stail(a), stail (b))))
def ssum(a,b): return szipwith(lambda x,y: x+y, a, b)
# тестовые примеры
n = 50
print("первые {} натуральных чисел:".format(n))
def intfrom(n): return cons(n, Lazy(lambda: intfrom(n+1)))
nats = intfrom(1)
print(stake(n, nats))
print("первые {} членов потока ряда Фибоначчи (НЕ экспоненциальный расчет):".format(n))
def fibgen(a,b): return cons(a, Lazy(lambda: fibgen(b, a+b)))
fibs = fibgen(0,1)
print(stake(n,fibs))
print("первые {} членов потока ряда Фибоначчи (мемоизированный экспоненциальный расчет):".format(n))
fibsexp = cons(0, cons(1, Lazy(lambda: ssum(stail(fibsexp), fibsexp))))
print(stake(n,fibsexp))
print("первые {} четных чисел:".format(n))
evens = sfilter(lambda x: x%2 == 0, intfrom(0))
print(stake(n, evens))
print("первые {} простых чисел через решето Эратосфена:".format(n))
def sieve(s):
r = sfilter(lambda x: x % car(s) != 0, stail(s))
return cons(car(s), Lazy(lambda: sieve(r)))
primesErat = sieve(intfrom(2))
print(stake(n, primesErat))
print("первые {} простых чисел через гипотезу Бертрана:".format(n))
def primesBert(): return cons(2, Lazy(lambda: sfilter(isprime, intfrom(3))))
def isprime(n):
def iter(ps):
if car(ps)*car(ps) > n: return True
elif n % car(ps) == 0: return False
else: return iter(stail(ps))
return iter(primesBert())
print(stake(n, primesBert()))
print ("частичные суммы натурального ряда:")
def partialsums (s):
def go(a, s): return cons(a+car(s), Lazy(lambda: go(a+car(s), stail(s))))
return go(0, s)
print(stake(50, partialsums(intfrom(1))))
print("первые {} чисел Хэмминга:".format(n))
def merge(a, b):
if car(a) < car(b): return cons(car(a), Lazy(lambda: merge(stail(a), b)))
elif car(a) > car(b): return cons(car(b), Lazy(lambda: merge(a, stail(b))))
else: return cons(car(a), Lazy(lambda: merge(stail(a), stail(b))))
def sscale (k, s): return smap(lambda x: k*x, s)
hamm = cons(1, Lazy(lambda: merge(sscale(2,hamm), merge(sscale(3,hamm), sscale(5, hamm)))))
print(stake(n, hamm))
результаты:
первые 50 натуральных чисел:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50]
первые 50 членов потока ряда Фибоначчи (НЕ экспоненциальный расчет):
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049]
первые 50 членов потока ряда Фибоначчи (мемоизированный экспоненциальный расчет):
[0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584, 4181, 6765, 10946, 17711, 28657, 46368, 75025, 121393, 196418, 317811, 514229, 832040, 1346269, 2178309, 3524578, 5702887, 9227465, 14930352, 24157817, 39088169, 63245986, 102334155, 165580141, 267914296, 433494437, 701408733, 1134903170, 1836311903, 2971215073, 4807526976, 7778742049]
первые 50 четных чисел:
[0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94, 96, 98]
первые 50 простых чисел через решето Эратосфена:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229]
первые 50 простых чисел через гипотезу Бертрана:
[2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97, 101, 103, 107, 109, 113, 127, 131, 137, 139, 149, 151, 157, 163, 167, 173, 179, 181, 191, 193, 197, 199, 211, 223, 227, 229]
частичные суммы натурального ряда:
[1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 66, 78, 91, 105, 120, 136, 153, 171, 190, 210, 231, 253, 276, 300, 325, 351, 378, 406, 435, 465, 496, 528, 561, 595, 630, 666, 703, 741, 780, 820, 861, 903, 946, 990, 1035, 1081, 1128, 1176, 1225, 1275]
первые 50 чисел Хэмминга:
[1, 2, 3, 4, 5, 6, 8, 9, 10, 12, 15, 16, 18, 20, 24, 25, 27, 30, 32, 36, 40, 45, 48, 50, 54, 60, 64, 72, 75, 80, 81, 90, 96, 100, 108, 120, 125, 128, 135, 144, 150, 160, 162, 180, 192, 200, 216, 225, 240, 243]
запустить и проверить можно на реплите: https://repl.it/
|