Iteraciones complejas en haskell
-
06-07-2019 - |
Pregunta
Tengo este programa de iteraciones complejas que escribí en TI Basic para realizar una iteración básica en un número complejo y luego dar la magnitud del resultado:
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
Lo que me gustaría hacer es hacer una versión de Haskell para impresionar a mi maestro en una tarea. Todavía estoy aprendiendo y llegué hasta aquí:
fractal ::(RealFloat a) =>
(Complex a) -> (Integer a) -> [Complex a]
fractal c n | n == a = z : fractal (z^2 + c)
| otherwise = error "Finished"
Lo que no sé hacer es cómo hacerlo solo iterar n
veces, así que quería que cuente a
y luego compararlo con n
para ver si había terminado.
¿Cómo haría esto?
Solución
La respuesta de Newacct muestra el camino:
fractal c n = take n $ iterate (\z -> z^2 + c) c
Iterate
genera la lista infinita de aplicaciones repetidas.
Ej:
iterate (2*) 1 == [1, 2, 4, 8, 16, 32, ...]
Con respecto al IO, tendrá que hacer algunos cálculos monádicos.
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)
Dado que Complex es convertible desde y hacia cadenas de forma predeterminada, puede usar readLn
para leerlos desde la consola (el formato es Re: + Im
).
Editar: solo por diversión, uno podría desugar la sintaxis monádica y las firmas de tipo que comprimirían todo el programa para esto:
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)
Editar # 2: algunos enlaces relacionados con el trazado y los conjuntos de Mandelbrot.
Otros consejos
Bueno, siempre puede generar una lista infinita de resultados de aplicaciones repetidas y tomar el primer n
de ellos usando take
. Y la función iterate
es útil para generar una lista infinita de resultados de aplicaciones repetidas.
Si desea una lista de valores:
fractalList c n = fractalListHelper c c n
where
fractalListHelper z c 0 = []
fractalListHelper z c n = z : fractalListHelper (z^2 + c) c (n-1)
Si solo te importa el último resultado:
fractal c n = fractalHelper c c n
where
fractalHelper z c 0 = z
fractalHelper z c n = fractalHelper (z^2 + c) c (n-1)
Básicamente, en ambos casos necesita una función auxiliar para el conteo y la acumulación. Ahora estoy seguro de que hay una manera mejor / menos detallada de hacer esto, pero yo mismo soy un novato de Haskell.
Editar: solo por diversión, un pliegue de una sola línea:
fractalFold c n = foldr (\c z -> z^2 + c) c (take n (repeat c))
(aunque, lo (tomar n (repetir c)) parece un poco innecesario, tiene que haber una forma aún mejor)