RosettaCodeData/Task/Van-Eck-sequence/Python/van-eck-sequence-4.py

80 lines
1.9 KiB
Python

'''Van Eck series by map-accumulation'''
from functools import reduce
from itertools import repeat
# vanEck :: Int -> [Int]
def vanEck(n):
'''First n terms of the vanEck sequence.'''
def go(xns, i):
x, ns = xns
prev = ns[x]
v = i - prev if 0 is not prev else 0
return (
(v, insert(ns, x, i)),
v
)
return [0] + mapAccumL(go)((0, list(repeat(0, n))))(
range(1, n)
)[1]
# -------------------------- TEST --------------------------
# main :: IO ()
def main():
'''The last 10 of the first N vanEck terms'''
print(
fTable(main.__doc__ + ':\n')(
lambda m: 'N=' + str(m), repr,
lambda n: vanEck(n)[-10:], [10, 1000, 10000]
)
)
# ----------------------- FORMATTING -----------------------
# fTable :: String -> (a -> String) ->
# (b -> String) -> (a -> b) -> [a] -> String
def fTable(s):
'''Heading -> x display function -> fx display function ->
f -> xs -> tabular string.
'''
def go(xShow, fxShow, f, xs):
ys = [xShow(x) for x in xs]
w = max(map(len, ys))
return s + '\n' + '\n'.join(map(
lambda x, y: y.rjust(w, ' ') + ' -> ' + fxShow(f(x)),
xs, ys
))
return go
# ------------------------ GENERIC -------------------------
# insert :: Array Int -> Int -> Int -> Array Int
def insert(xs, i, v):
'''An array updated at position i with value v.'''
xs[i] = v
return xs
# mapAccumL :: (acc -> x -> (acc, y)) -> acc -> [x] -> (acc, [y])
def mapAccumL(f):
'''A tuple of an accumulation and a list derived by a
combined map and fold,
with accumulation from left to right.
'''
def go(a, x):
tpl = f(a[0], x)
return (tpl[0], a[1] + [tpl[1]])
return lambda acc: lambda xs: (
reduce(go, xs, (acc, []))
)
# MAIN ---
if __name__ == '__main__':
main()