72 lines
1.6 KiB
Python
72 lines
1.6 KiB
Python
'''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()
|