RosettaCodeData/Task/Cantor-set/Python/cantor-set-3.py

72 lines
1.6 KiB
Python
Raw Permalink Normal View History

2023-07-01 11:58:00 -04:00
'''Cantor set strings as both model and display.'''
from itertools import (chain, islice)
# cantorLines :: Int -> String
def cantorLines(n):
'''N levels of cantor segmentation,
obtained and displayed in the
form of lines of block characters.
'''
return '\n'.join(
[''.join(x) for x in islice(
iterate(cantor)(
[3 ** (n - 1) * '']
), n
)]
)
# cantor :: [String] -> [String]
def cantor(xs):
'''A cantor line derived from its predecessor.'''
def go(s):
m = len(s) // 3
blocks = s[0:m]
return [
blocks, m * ' ', blocks
] if '' == s[0] else [s]
return concatMap(go)(xs)
# MAIN ----------------------------------------------------
# main :: IO ()
def main():
'''Testing cantor line generation to level 5'''
print(
cantorLines(5)
)
# GENERIC -------------------------------------------------
# concatMap :: (a -> [b]) -> [a] -> [b]
def concatMap(f):
'''A concatenated list over which a function has been mapped.
The list monad can be derived by using a function f which
wraps its output in a list,
(using an empty list to represent computational failure).'''
return lambda xs: list(
chain.from_iterable(map(f, xs))
)
# 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)
# MAIN ---
if __name__ == '__main__':
main()