Komplexe Iterationen in Haskell
-
06-07-2019 - |
Frage
Ich habe dieses komplexe Iterationen -Programm, das ich in Ti Basic geschrieben habe, um eine grundlegende Iteration mit einer komplexen Zahl durchzuführen und dann die Größe des Ergebnisses zu geben:
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
Ich möchte eine Haskell -Version davon machen, um meinen Lehrer in einer Aufgabe zu begeistern. Ich lerne immer noch nur und bin so weit gekommen:
fractal ::(RealFloat a) =>
(Complex a) -> (Integer a) -> [Complex a]
fractal c n | n == a = z : fractal (z^2 + c)
| otherwise = error "Finished"
Was ich nicht weiß, wie ich es nur iterieren kann n
Zeiten, also wollte ich es zählen lassen a
und dann vergleichen Sie es mit n
um zu sehen, ob es fertig war.
Wie würde ich das vorgehen?
Lösung
Die Antwort von NewaccT zeigt den Weg:
fractal c n = take n $ iterate (\z -> z^2 + c) c
Iterate
Generiert die unendliche Liste der wiederholten Anwendungen. Ex:
iterate (2*) 1 == [1, 2, 4, 8, 16, 32, ...]
In Bezug auf das IO müssen Sie einige monadische Berechnungen durchführen.
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)
Da der Komplex standardmäßig von und zu Zeichenfolgen konvertierbar ist, können Sie verwenden readLn
sie aus der Konsole zu lesen (Format ist Re :+ Im
).
Bearbeiten: Nur zum Spaß könnte man die monadische Syntax und die Signaturen eingeben, die das gesamte Programm dazu komprimieren würden:
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)
Bearbeiten Nr. 2: Einige Links im Zusammenhang mit den Sätzen von Plotten und Mandelbrot.
Andere Tipps
Nun, Sie können immer eine unendliche Liste von Ergebnissen von wiederholten Anwendungen generieren und die erste nehmen n
von ihnen benutzen take
. Und die iterate
Funktion ist nützlich, um eine unendliche Liste von Ergebnissen wiederholter Anwendungen zu generieren.
Wenn Sie eine Liste von Werten möchten:
fractalList c n = fractalListHelper c c n
where
fractalListHelper z c 0 = []
fractalListHelper z c n = z : fractalListHelper (z^2 + c) c (n-1)
Wenn Sie sich nur um das letzte Ergebnis kümmern:
fractal c n = fractalHelper c c n
where
fractalHelper z c 0 = z
fractalHelper z c n = fractalHelper (z^2 + c) c (n-1)
Grundsätzlich benötigen Sie in beiden Fällen eine Helferfunktion für die Zählung und Akkumulation. Jetzt bin ich mir sicher, dass es eine bessere/weniger ausführliche Möglichkeit gibt, dies zu tun, aber ich bin selbst ein Haskell -Neuling.
Bearbeiten: Nur für Kicks, ein FILDR-One-Liner:
fractalFold c n = foldr (\c z -> z^2 + c) c (take n (repeat c))
(Obwohl das (Take N (Repeat C)) etwas unnötig erscheint, muss es einen noch besseren Weg geben)