Сложные итерации в haskell - PullRequest
       14

Сложные итерации в haskell

2 голосов
/ 12 сентября 2009

У меня есть эта сложная итерационная программа, которую я написал в TI Basic, чтобы выполнить базовую итерацию для комплексного числа, а затем дать величину результата:

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

Что я хотел бы сделать, так это сделать версию на Хаскелле, чтобы удивить моего учителя при выполнении задания. Я все еще только учусь и получил это далеко:

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

Что я не знаю, как это сделать, так это сделать так, чтобы он повторялся только n раз, поэтому я хотел, чтобы он подсчитал a, а затем сравнил его с n, чтобы увидеть, завершился ли он.

Как бы я поступил об этом?

Ответы [ 3 ]

4 голосов
/ 12 сентября 2009

Newacct ответ показывает путь:

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

Iterate генерирует бесконечный список повторных заявлений. Пример:

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

Что касается ввода / вывода, вам придется выполнить несколько монадических вычислений.

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)

Так как Complex по умолчанию конвертируем из и в строки, вы можете использовать readLn для чтения их из консоли (формат Re :+ Im).

Редактировать: Ради интереса можно было бы десагаровать монадический синтаксис и сигнатуры типов, которые бы сжимали всю программу до следующего:

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)

Редактировать # 2: Некоторые ссылки, связанные с построением и множествами Мандельброта.

3 голосов
/ 12 сентября 2009

Ну, вы всегда можете сгенерировать бесконечный список результатов повторных заявок и взять первые n из них, используя take. А функция iterate полезна для генерации бесконечного списка результатов повторных приложений.

2 голосов
/ 12 сентября 2009

Если вы хотите список значений:

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

Если вы заботитесь только о последнем результате:

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

В принципе, в обоих случаях вам нужна вспомогательная функция для подсчета и накопления. Теперь я уверен, что есть лучший / менее многословный способ сделать это, но я в значительной степени новичок в Haskell.

Редактировать: только для ударов, одна строчка:

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

(хотя, (возьмите n (повторите c)) вещь кажется ненужной, должен быть еще лучший способ)

...