Pascal's triangle: Difference between revisions

Content added Content deleted
m (Updated description and link for Fōrmulæ solution)
Line 4,774: Line 4,774:
===Functional===
===Functional===


Deriving finite and non-finite lists of pascal rows from a simple '''nextPascal''' step function:
The itertools module yields a simple functional definition of '''scanl''' in terms of '''accumulate''', and '''zipWith''' can be defined in terms either of '''itertools.starmap''', or the base '''map'''.

With a scanl and a zipWith to hand, we can derive both finite and non-finite lists of pascal rows from a simple '''nextPascal''' step function:


{{Works with|Python|3.7}}
{{Works with|Python|3.7}}
Line 4,789: Line 4,787:
'''A row of Pascal's triangle
'''A row of Pascal's triangle
derived from a preceding row.'''
derived from a preceding row.'''
return zipWith(add)([0] + xs)(xs + [0])
return list(
map(add, [0] + xs, xs + [0])
)




Line 4,804: Line 4,804:
def go(a, _):
def go(a, _):
return nextPascal(a)
return nextPascal(a)

return scanl(go)([1])(
range(1, n)
return accumulate(
chain([[1]], range(1, n)),
go
)
)




# TESTS ---------------------------------------------------
# ------------------------ TESTS -------------------------
# main :: IO ()
# main :: IO ()
def main():
def main():
Line 4,815: Line 4,817:
- taking from a non-finite stream of rows,
- taking from a non-finite stream of rows,
- or constructing a finite list of rows.'''
- or constructing a finite list of rows.'''
print(unlines(map(
print('\n'.join(map(
showPascal,
showPascal,
[
[
take(7)(
islice(
pascalTriangle() # Non finite,
pascalTriangle(), # Non finite,
7
),
),
finitePascalRows(7) # finite.
finitePascalRows(7) # finite.
Line 4,840: Line 4,843:




# GENERIC -------------------------------------------------
# ----------------------- GENERIC ------------------------



# center :: Int -> Char -> String -> String
# center :: Int -> Char -> String -> String
Line 4,856: Line 4,858:
# iterate :: (a -> a) -> a -> Gen [a]
# iterate :: (a -> a) -> a -> Gen [a]
def iterate(f):
def iterate(f):
'''An infinite list of repeated applications of f to x.'''
'''An infinite list of repeated
applications of f to x.
'''
def go(x):
def go(x):
v = x
v = x
Line 4,862: Line 4,866:
yield v
yield v
v = f(v)
v = f(v)
return lambda x: go(x)
return go


# scanl :: (b -> a -> b) -> b -> [a] -> [b]
def scanl(f):
'''scanl is like reduce, but returns a succession of
intermediate values, building from the left.'''
return lambda a: lambda xs: (
accumulate(chain([a], xs), f)
)


# 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: (
xs[0:n]
if isinstance(xs, list)
else list(islice(xs, n))
)


# unlines :: [String] -> String
def unlines(xs):
'''A single string derived by the intercalation
of a list of strings with the newline character.'''
return '\n'.join(xs)


# zipWith :: (a -> b -> c) -> [a] -> [b] -> [c]
def zipWith(f):
'''A list constructed by zipping with a
custom function, rather than with the
default tuple constructor.'''
return lambda xs: lambda ys: (
list(map(f, xs, ys))
)