# Ascii fractals

Getting hypnotized by the shape of a fractal is certainly fascinating. In this blog, we will write a Haskell program that creates fractals from a base pattern. The recursive nature of the fractals allow a simple implementation in Haskell. In case you don't know what a fractal is, I invite you to take a look at the Wikipedia page.

So, let's start coding. First let's write the types for what we want.

type Pattern = [[Char]]
fractalize :: Pattern -> Int -> Pattern
render :: Pattern -> String

The function fractalize takes a base pattern and the number of times that we want to augment it. It returns the resulting fractal.

Given a pattern, let $n, m$ be the number of rows and columns of the base pattern. We define:

$charAt(k, i, k)= \begin{cases} p[i][j], & \text{if } k = 1 \\ \text{' '} & \text{if } charAt(k - 1, \frac{i}n, \frac{j}m) = \text{' '} \\ p[i\bmod n][j\bmod m], & \text{otherwise} \end{cases}$

This function returns the character in the resulting fractal at the specified position.

Let's translate it into Haskell code:

fractalize :: Pattern -> Int -> Pattern
fractalize [] _ = []
fractalize pat k = [ [ charAt k i j | j <- [0..m^k - 1] ] | i <- [0..n^k - 1] ]
where
n = length pat
m = length (head pat)
charAt k i j
| k <= 1 = pat!!i!!j
| ' ' == charAt (k - 1) (idivn) (jdivm) = ' '
| otherwise = pat!!(imodn)!!(jmodm)

render :: Pattern -> String
render = unlines

Let's try this base pattern:

pattern1 :: Pattern
pattern1 = [ " # "
, "###"
, " # "]

Fractalizing the pattern three times gives:

             #
###
#
#  #  #
#########
#  #  #
#
###
#
#        #        #
###      ###      ###
#        #        #
#  #  #  #  #  #  #  #  #
###########################
#  #  #  #  #  #  #  #  #
#        #        #
###      ###      ###
#        #        #
#
###
#
#  #  #
#########
#  #  #
#
###
#

Cool! let's try another pattern!

pattern2 :: Pattern
pattern2 = [ "# #"
, " # "
, "# #"]
# #   # #         # #   # #
#     #           #     #
# #   # #         # #   # #
# #               # #
#                 #
# #               # #
# #   # #         # #   # #
#     #           #     #
# #   # #         # #   # #
# #   # #
#     #
# #   # #
# #
#
# #
# #   # #
#     #
# #   # #
# #   # #         # #   # #
#     #           #     #
# #   # #         # #   # #
# #               # #
#                 #
# #               # #
# #   # #         # #   # #
#     #           #     #
# #   # #         # #   # #

Awesome!

The glue code of our main program is very simple. The number of augments is passed as an argument to the program.

main :: IO ()
main = getK >>= putStr . render . fractalize pattern1
where getK = read . head <\$> getArgs

In order to run the example by yourself, get the full code from here and run:

runhaskell fractals.hs 3

We are done! Try your base patterns and have fun!