Codewars - Sierpinski's Gasket

The Codewars Sierpinski's Gasket challenge asks us to draw Sierpinski's triangle using the letter "L" and spaces. Per usual I'm trying it in both Python and Haskell; this time I solved it in Python first.

Hea come da spoilers.

Python

def sierpinski(x):
  """Produce a 'triangle' of Ls, recursively x deep"""

  if x == 0:
    return "L"

  triangle = sierpinski(x - 1)
  return above(triangle, beside(triangle, triangle))

def above(top, bottom):
  """Combine the top and bottom triangle text."""
  return top + "\n" + bottom

def beside(left, right):
  """Combine left and right triangle text. Assumes left and right strings have
     same number of newlines.
  """

  def widen_row(x, row):
    if x <= 0: return row
    return widen_row(x - 1, row + " ")

  left_rows = left.split("\n")
  right_rows = right.split("\n")
  width = len(left_rows[-1])
  combined = []

  for i in range(len(left_rows)):
    combined.append(
      widen_row(width - len(left_rows[i]), left_rows[i])
      + " "
      + right_rows[i])

  return "\n".join(combined)

It was fun to allow my Python code to be somewhat influenced by things I've picked up from functional languages. My use of small, internal helper functions and recursively describing a level of the triangle in terms of "above" and "beside" other triangles was heavily influenced by work I've done in Racket.

Haskell

import Data.List(intercalate)

-- | Produce the Sierpinsky Triangle as a string of "L "s
sierpinsky :: Integral a => a -> String
sierpinsky 0 = "L"
sierpinsky x = above triangle $ beside triangle triangle where
  triangle = sierpinsky $ x - 1

-- | Put one string above another by joining them with a newline
above :: String -> String -> String
above top bottom = top ++ "\n" ++ bottom

-- | Place one string beside another by joining each line with a
--   consistant spacing
beside :: String -> String -> String
beside left right = intercalate "\n" $ zipWith (nextTo width) (lines left)
(lines right)  where
  width = length $ last $ lines right
  nextTo x l r = l ++ replicate (x - (length l)) ' ' ++ " " ++ r

This used the same rough outline as the Python version; the spelling is consistent with that used for the Codewars challenge, not sure it's right though.

It is quite satisfying that the results almost look like descriptions throughout: can you see where it says "lines on the left, with adjusted width, next to lines on the right?"

Comparison

Haskell continues to require a good deal more mental effort; composing functions is getting easier but still involves a lot of trial and error on my part.

Nice solutions to study

The top Codewars solutions for Python and Haskell implemented the same concept with fewer lines. Worth mulling. In this case I do kind of like expressing the fractal in terms of "above," "beside," and "triangle" rather than the minimalist variable names they tend to favor.