views:

332

answers:

3

Hi I have this complex iterations program I wrote in TI Basic to perform a basic iteration on a complex number and then give the magnitude of the result:

INPUT “SEED?”, C
INPUT “ITERATIONS?”, N
C→Z
For (I,1,N)
Z^2 + C → Z
DISP Z
DISP “MAGNITUDE”, sqrt ((real(Z)^2 + imag(Z)^2))
PAUSE
END

What I would like to do is make a Haskell version of this to wow my teacher in an assignment. I am still only learning and got this far:

fractal ::(RealFloat a) =>
          (Complex a) -> (Integer a) -> [Complex a]
fractal c n | n == a = z : fractal (z^2 + c)
   | otherwise = error "Finished"

What I don't know how to do is how to make it only iterate n times, so I wanted to have it count up a and then compare it to n to see if it had finished.

How would I go about this?

+3  A: 

Well you can always generate an infinite list of results of repeated applications and take the first n of them using take. And the iterate function is useful for generating an infinite list of results of repeated applications.

newacct
+2  A: 

If you'd like a list of values:

fractalList c n = fractalListHelper c c n
                  where 
                     fractalListHelper z c 0 = []
                     fractalListHelper z c n = z : fractalListHelper (z^2 + c) c (n-1)

If you only care about the last result:

fractal c n = fractalHelper c c n
                  where
                    fractalHelper z c 0 = z
                    fractalHelper z c n = fractalHelper (z^2 + c) c (n-1)

Basically, in both cases you need a helper function to the counting and accumulation. Now I'm sure there's a better/less verbose way to do this, but I'm pretty much a Haskell newbie myself.

Edit: just for kicks, a foldr one-liner:

fractalFold c n = foldr (\c z -> z^2 + c) c (take n (repeat c))

(although, the (take n (repeat c)) thing seems kind of unnecessary, there has to be an even better way)

sbk
I think it's better to use `foldl'` instead of `foldr` like `fractalFold c n = foldl' (\z c -> z^2 + c) c (take n (repeat c))`. Because `foldr` is lazy. It means it creates thunks as the length of given list, but return type of `fractalFold` doesn't need to be lazy.
nwn
+3  A: 

Newacct's answer shows the way:

fractal c n = take n $ iterate (\z -> z^2 + c) c

Iterate generates the infinite list of repeated applications. Ex:

iterate (2*) 1 == [1, 2, 4, 8, 16, 32, ...]

Regarding the IO, you'll have to do some monadic computations.

import Data.Complex
import Control.Monad

fractal c n = take n $ iterate (\z -> z^2 + c) c

main :: IO ()
main = do
    -- Print and read (you could even omit the type signatures here)
    putStr "Seed: "
    c <- readLn :: IO (Complex Double)

    putStr "Number of iterations: "
    n <- readLn :: IO Int

    -- Working with each element the result list
    forM_ (fractal c n) $ \current -> do
        putStrLn $ show current
        putStrLn $ "Magnitude: " ++ (show $ magnitude current)

Since Complex is convertible from and to strings by default, you can use readLn to read them from the console (format is Re :+ Im).

Edit: Just for fun, one could desugar the monadic syntax and type signatures which would compress the whole programm to this:

main = 
    (putStr "Seed: ") >> readLn >>= \c -> 
    (putStr "Number of iterations: ") >> readLn >>= \n -> 
    forM_ (take n $ iterate (\z -> z^2 + c) c) $ \current ->
    putStrLn $ show current ++ "\nMagnitude: " ++ (show $ magnitude current)

Edit #2: Some Links related to plotting and Mandelbrot's sets.

Dario
Thanks, is there any way to perhaps get this drawn on a graph with some crazy colours if the results appear in the mandlebrot set (when magnitude < 2)?
Jonno_FTW
Edited my post - Some very interesting links ;-)
Dario
I am so compiling all this and the fractal plotter and sending my teacher an executable.
Jonno_FTW