149 lines
3.1 KiB
Python
149 lines
3.1 KiB
Python
'''Loops/Increment loop index within loop body.'''
|
|
|
|
from itertools import islice, takewhile
|
|
from functools import reduce
|
|
import operator
|
|
|
|
|
|
# main :: IO ()
|
|
def main():
|
|
'''Defines a list value, while printing a stream
|
|
of intermediate values during computation.
|
|
'''
|
|
gt = curry(operator.gt)
|
|
fst = operator.itemgetter(0)
|
|
|
|
list(takewhile(compose(gt(43), fst), series()))
|
|
|
|
|
|
# series :: (Int, Int) -> [(Int, Int)]
|
|
def series():
|
|
'''Non finite series, defined as a generator
|
|
with IO side-effects (to the print channel).
|
|
'''
|
|
def go(tpl):
|
|
if isPrime(tpl[1]):
|
|
# Side effect.
|
|
print(showTuple(tpl))
|
|
# Value.
|
|
return splitArrow(succ)(dbl)(tpl)
|
|
else:
|
|
return secondArrow(succ)(tpl)
|
|
|
|
return iterate(go)(
|
|
(1, 42)
|
|
)
|
|
|
|
|
|
# isPrime :: Int -> Bool
|
|
def isPrime(n):
|
|
'''True if n is prime.'''
|
|
if n in (2, 3):
|
|
return True
|
|
if 2 > n or 0 == n % 2:
|
|
return False
|
|
if 9 > n:
|
|
return True
|
|
if 0 == n % 3:
|
|
return False
|
|
|
|
def p(x):
|
|
return 0 == n % x or 0 == n % (2 + x)
|
|
|
|
return not any(map(p, range(5, 1 + int(n ** 0.5), 6)))
|
|
|
|
|
|
# showTuple :: (Int, Int) -> String
|
|
def showTuple(tpl):
|
|
'''Second integer shown with comma-chunked digits.'''
|
|
return '{:2} -> {:20,}'.format(*tpl)
|
|
|
|
|
|
# -------------------------GENERIC-------------------------
|
|
|
|
# compose :: ((a -> a), ...) -> (a -> a)
|
|
def compose(*fs):
|
|
'''Composition, from right to left,
|
|
of a series of functions.
|
|
'''
|
|
return lambda x: reduce(
|
|
lambda a, f: f(a),
|
|
fs[::-1], x
|
|
)
|
|
|
|
|
|
# curry :: ((a, b) -> c) -> a -> b -> c
|
|
def curry(f):
|
|
'''A curried function derived
|
|
from an uncurried function.
|
|
'''
|
|
return lambda x: lambda y: f(x, y)
|
|
|
|
|
|
# dbl :: Int -> Int -> Int
|
|
def dbl(x):
|
|
'''2 * x'''
|
|
return x + x
|
|
|
|
|
|
# drop :: Int -> [a] -> [a]
|
|
# drop :: Int -> String -> String
|
|
def drop(n):
|
|
'''The sublist of xs beginning at
|
|
(zero-based) index n.
|
|
'''
|
|
def go(xs):
|
|
take(n)(xs)
|
|
return xs
|
|
return go
|
|
|
|
|
|
# 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 go
|
|
|
|
|
|
# secondArrow :: (b -> c) -> (a, b...) -> (a, c ...)
|
|
def secondArrow(f):
|
|
'''A simple function lifted to one which applies
|
|
to a tuple, transforming only its second value.
|
|
'''
|
|
return lambda tpl: (tpl[0], f(tpl[1]))
|
|
|
|
|
|
# splitArrow (***) :: (a -> b) -> (c -> d) -> ((a, c) -> (b, d))
|
|
def splitArrow(f):
|
|
'''A function from (x, y) to a tuple of (f(x), g(y))
|
|
'''
|
|
return lambda g: lambda tpl: (f(tpl[0]), g(tpl[1]))
|
|
|
|
|
|
# succ :: Enum a => a -> a
|
|
def succ(x):
|
|
'''The successor of a value.
|
|
For numeric types, (1 +).
|
|
'''
|
|
return 1 + x
|
|
|
|
|
|
# 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: list(islice(xs, n))
|
|
|
|
|
|
# MAIN ---
|
|
if __name__ == '__main__':
|
|
main()
|