RosettaCodeData/Task/Ethiopian-multiplication/Python/ethiopian-multiplication-4.py

124 lines
2.8 KiB
Python

'''Ethiopian multiplication'''
from functools import reduce
# ethMult :: Int -> Int -> Int
def ethMult(n):
'''Ethiopian multiplication of n by m.'''
def doubled(x):
return x + x
def halved(h):
qr = divmod(h, 2)
if 0 < h:
print('halve:', str(qr).rjust(8, ' '))
return Just(qr) if 0 < h else Nothing()
def addedWhereOdd(a, remx):
odd, x = remx
if odd:
print(
str(a).rjust(2, ' '), '+',
str(x).rjust(3, ' '), '->',
str(a + x).rjust(3, ' ')
)
return a + x
else:
print(str(x).rjust(8, ' '))
return a
return lambda m: reduce(
addedWhereOdd,
zip(
unfoldr(halved)(n),
iterate(doubled)(m)
),
0
)
# TEST -------------------------------------------------
def main():
'''Tests of multiplication.'''
print(
'\nProduct: ' + str(
ethMult(17)(34)
),
'\n_______________\n'
)
print(
'\nProduct: ' + str(
ethMult(34)(17)
)
)
# GENERIC -------------------------------------------------
# Just :: a -> Maybe a
def Just(x):
'''Constructor for an inhabited Maybe (option type) value.'''
return {'type': 'Maybe', 'Nothing': False, 'Just': x}
# Nothing :: Maybe a
def Nothing():
'''Constructor for an empty Maybe (option type) value.'''
return {'type': 'Maybe', 'Nothing': True}
# 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)
# showLog :: a -> IO String
def showLog(*s):
'''Arguments printed with
intercalated arrows.'''
print(
' -> '.join(map(str, s))
)
# unfoldr(lambda x: Just((x, x - 1)) if 0 != x else Nothing())(10)
# -> [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
# unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
def unfoldr(f):
'''Dual to reduce or foldr.
Where catamorphism reduces a list to a summary value,
the anamorphic unfoldr builds a list from a seed value.
As long as f returns Just(a, b), a is prepended to the list,
and the residual b is used as the argument for the next
application of f.
When f returns Nothing, the completed list is returned.'''
def go(v):
xr = v, v
xs = []
while True:
mb = f(xr[0])
if mb.get('Nothing'):
return xs
else:
xr = mb.get('Just')
xs.append(xr[1])
return xs
return lambda x: go(x)
# MAIN ---
if __name__ == '__main__':
main()