RosettaCodeData/Task/Fusc-sequence/Python/fusc-sequence-2.py

127 lines
2.5 KiB
Python

'''Fusc sequence'''
from itertools import chain, count, islice
from operator import itemgetter
# As an infinite stream of terms,
# infiniteFusc :: [Int]
def infiniteFusc():
'''Fusc sequence.
OEIS A2487
'''
def go(step):
isEven, n, xxs = step
x, xs = xxs[0], xxs[1:]
if isEven:
nxt = n + x
return not isEven, nxt, xxs + [nxt]
else:
return not isEven, x, xs + [x]
return chain(
[0, 1],
map(
itemgetter(1),
iterate(go)(
(True, 1, [1])
)
)
)
# Or as a function over an integer:
# fusc :: Int -> Int
def fusc(i):
'''Fusc sequence'''
def go(n):
if 0 == n:
return (1, 0)
else:
x, y = go(n // 2)
return (x + y, y) if 0 == n % 2 else (
x, x + y
)
return 0 if 1 > i else (
go(i - 1)[0]
)
# firstFuscOfEachMagnitude ::
def firstFuscOfEachMagnitude():
'''Non-finite stream of each term
in OEIS A2487 that requires an
unprecedented quantity of decimal digits.
'''
a2487 = enumerate(map(fusc, count()))
def go(e):
limit = 10 ** e
return next(
(i, x) for i, x in a2487
if limit <= x
)
return (
chain([(0, 0)], map(go, count(1)))
)
# --------------------------TEST---------------------------
# main :: IO ()
def main():
'''Tests'''
print('First 61 terms:')
print(showList(
take(61)(
map(fusc, count())
)
))
print('\nFirst term of each decimal magnitude:')
print('(Index, Term):')
ixs = firstFuscOfEachMagnitude()
for _ in range(0, 5):
print(next(ixs))
# -------------------------GENERIC-------------------------
# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
'''An infinite list of repeated
applications of f to x.
'''
def go(x):
v = x
while True:
yield v
v = f(v)
return lambda x: go(x)
# showList :: [a] -> String
def showList(xs):
'''Compact stringification of a list.'''
return '[' + ','.join(repr(x) for x in xs) + ']'
# take :: Int -> [a] -> [a]
# take :: Int -> String -> String
def take(n):
'''The prefix of xs of length n,
or xs itself if n > length xs.
'''
return lambda xs: (
xs[0:n]
if isinstance(xs, (list, tuple))
else list(islice(xs, n))
)
# MAIN ---
if __name__ == '__main__':
main()