Как структурировать код Haskell для IO?

Я полностью документирую каждый открытый метод в каждом классе API. Классы, которые имеют общедоступных участников, но которые не предназначаются для внешнего потребления, заметно отмечены в классе javadoc. Я также документирую каждый защищенный метод в каждом классе API, хотя до меньшей степени. Это идет на идею, что у любого разработчика, который расширяет класс API, уже будет справедливое понятие того, что продолжается.

Наконец, я буду иногда документировать частный и закрытые методы пакета для моего собственного преимущества. Для любого метода или поля, что я думаю, нужно некоторое объяснение в его использовании, получит документацию, независимо от его видимости.

5
задан JS. 20 September 2009 в 21:32
поделиться

4 ответа

yairchu имеет хороший ответ для вашего проблема с printBody. Ваш главный вопрос, как структурировать вашу программу, чтобы вы могли распечатать каждый шаг, немного сложнее. Предположительно, вы хотите сохранить runSim или что-то в этом роде в чистом виде, поскольку он просто запускает симуляцию, а ввод-вывод на самом деле не его работа.

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

Измените runSim , чтобы получить список шагов:

runSim :: [Body] -> Double -> [[Body]]
-- now returns a list of bodys, but no terminating condition
runSim bodys numSteps dtparam = nextBodys : runSim nextBodys dtparam
    where nextBodys = map (integratePos dtparam . integrateVel dtparam) 
                          (calculateForce bodys)

Теперь main может выполнить любое количество шагов моделирования и распечатать их:

main = mapM_ (mapM_ print) (take 100 $ runSim [earth, sun] 0.05)

Опять же, я предполагаю, что, следуя совету yairchu, у вас есть Body deriving Show , так что print будет работать. mapM_ похож на map , за исключением того, что для сопоставления требуется монадическая (здесь побочная) функция (заканчивается на M) и не возвращает список (заканчивается на _) . Так что на самом деле это больше похоже на для каждого в схеме или что-то в этом роде.

Альтернатива - оставить свой runSim и написать цикл печати, который запускается только по одному шагу за раз:

printLoop :: Integer -> [Body] -> IO [Body]
printLoop 0 bodies = return bodies
printLoop n bodies = do
    let planets = runSim bodies 1 0.05
    mapM_ print planets -- still need to have Body deriving Show
    printLoop (n-1) planets

main = do
    printLoop 100 [earth, sun]
    return ()
7
ответ дан 18 December 2019 в 13:16
поделиться

Что касается

printInfo :: Body -> Body
printInfo b = do
    putStrLn b
    b

Если только " type Body = String ", вы не можете выполнить putStrLn в Body .

ghci> :t putStrLn
putStrLn :: String -> IO ()

putStrLn требует String . Вы можете использовать putStrLn. покажите или

$ hoogle "Show a => a -> IO ()"
Prelude print :: Show a => a -> IO ()

используйте print .

Теперь, делая разумные предположения о типе Body , printInfo тип неверен. Поскольку он вызывает putStrLn , он должен заканчиваться "-> IO Something".

Здесь:

printBody :: Body -> IO Body
printBody b = do
  print b
  b

Последняя строка здесь неверна. b относится к типу Body , но там должны быть данные IO Body . Как мы можем сделать это преобразование? Использование return :: Monad m => a -> ma .

Итак, вот рабочая версия:

printBody :: Body -> IO Body
printBody b = do
  print b
  return b
4
ответ дан 18 December 2019 в 13:16
поделиться

Для выполнения ввода-вывода вы должны быть в монаде ввода-вывода:

printInfo :: Body -> IO Body
printInfo b = do
  putStrLn b
  return b

И чтобы вызвать эту функцию из вашей функции runSim , она должна находиться внутри ввода-вывода. монада:

runSim :: [Body] -> Integer -> Double -> IO [Body]

(Хотя могут быть более эффективные способы организации вашей функции.)

Это дело с монадой нетривиально. Это величайшая сила Haskell, но когда вы впервые сталкиваетесь с ней, трудно осознать ее. Я предлагаю проработать учебное пособие, подобное этому:

http://learnyouahaskell.com/

В частности, это поможет вам начать:

http://learnyouahaskell.com/input-and-output

Существует множество руководств по монадам, в которых гораздо больше деталей (написание одного - первое, что делают все после того, как они с ними познакомятся). Ссылки с haskell.org - ваши друзья.

2
ответ дан 18 December 2019 в 13:16
поделиться

Для записи, вот решение, которое я пришел Да ладно, думаю, сейчас я перекодирую его с бесконечными списками, хотя:


runSim :: ([Body], [IO ()]) -> Integer -> Double -> ([Body], [IO ()]) 
runSim (bodys,bodyActions) 0 dtparam = (bodys, bodyActions)
runSim (bodys,bodyActions) numSteps dtparam = runSim (movedBodys, newBodyActions) (numSteps-1) dtparam
                where movedBodys = (map (integratePos dtparam . integrateVel dtparam) (calculateForce bodys))
                      newBodyActions = bodyActions ++ map print bodys

main = do let planets = runSim ([earth, sun],[]) 100 0.05 sequence $ snd planets

Еще раз спасибо всем!

1
ответ дан 18 December 2019 в 13:16
поделиться
Другие вопросы по тегам:

Похожие вопросы: