Отслеживайте программные переменные в Haskell как императивные программы - PullRequest
3 голосов
/ 24 июля 2010

Мне трудно понять, как что-то изменить, каждый раз, когда пользователь взаимодействует с моей программой.Трудно объяснить, поэтому вот пример (Haskell + wxhaskell):

simulate :: Int -> Frame () -> IO ()
simulate qNr window = do
 fdata <- readFile "qarchive"
 case (split (listTake (split fdata '\n') qNr 0) '#') of
  (qst:a:b:c:coralt:answer:x) -> do
   -- GUI Controls Initialization (buttons,text,etc...) 
   nextButton <- button window [text := "Next Question ->", on command := set infoField [text := "Next Question"], position := pt 185 155]
   return ()

main :: IO ()
main = start gui

gui :: IO ()
gui = do
 window <- frame [text := "Question program", clientSize := sz 640 480]
 headerText <- staticText window [text := "Title Text", fontSize := 20, position := pt 5 5]
 simulate 0 window
 return ()

Я хочу, чтобы некоторые виджеты менялись при нажатии кнопки «Следующий вопрос».Я хочу изменить эти виджеты на некоторые значения, которые я читаю из файла.Как я могу отслеживать текущий номер вопроса?На самом деле я не могу увеличивать QuestionNumber как переменную, поскольку Haskell не разрешает такие вещи.Я думаю, есть другой способ сделать это.

Пример:

Initialize GUI
Read data from file
If button is pressed, increment question number by 1 and change widgets.

Как вы решаете эту проблему функционально?

Ответы [ 4 ]

5 голосов
/ 24 июля 2010

Аргументы функций - это ваши переменные.Когда пользователь вводит новые значения, передайте эти значения функциям.

Например, простая программа, которая обновляет значение на основе пользовательского ввода:

main = loop 0

loop n = do
    print n
    v <- read `fmap` getLine
    loop (n + v)

Обратите внимание на рекурсивные вызовы 'loop'каждый раз передается различное значение, в зависимости от того, что предоставил пользователь.

Это фундаментальный способ мышления в функциональном программировании - то, что будет локальной изменяемой переменной в цикле в императивной программе, становитсяпараметр рекурсивной функции в функциональной программе.

2 голосов
/ 28 июля 2010

К сожалению, поскольку wxHaskell - это основанная на событиях структура, ответы Дона и Зака ​​не применимы.

То, что вы должны сделать здесь, - это выделить изменчивую переменную , как вы это сделали бы в императивном языке. Для этого WxHaskell предлагает функцию variable. Вот (неполный) пример:

gui = do
        ...
        counter <- variable [value := 1 :: Int]  -- allocate mutable variable
        button  <- button window [ text       := "Count!"
                                 , on command := next counter button]
    where
    next counter button = do
        n <- get counter value         -- get its value
        set button  [text  := show n]
        set counter [value := n+1]     -- set its value

Обратите внимание, что wxHaskell поставляется с большим количеством примеров исходного кода . В частности, wx/ImageViewer.hs имеет изменяемую переменную.

Однако, за исключением особых ситуаций, подобных этой, полезно избегать изменчивых переменных, таких как чума. (На самом деле, они тоже создают беспорядок в wxHaskell, просто здесь их трудно избежать.) Альтернативы включают переосмысление вашего кода, накопление параметров, использование типов формы s -> (a,s) и монады состояний.

1 голос
/ 24 июля 2010

Одним из способов сделать это на функциональном языке является проработка вашего состояния через ваши функции.Некоторые из функций, вероятно, будут обрабатываться монадами, такими как получение состояния клавиатуры, поэтому вам не придется справляться с этим самостоятельно.Пример (более или менее псевдокод):

someFunction :: SomeDataTypeThatRepresentsState -> a ... -> (SDTTRS, a...) (change to fit reality of course)
someFunction x y .... | x == WeHaveKeyboardInput = someFunction dowhatever.....
                      | someFunction dowhateverelse

Это должно дать вам представление о том, как начать работу.

РЕДАКТИРОВАТЬ:

Я должен был упомянуть монады болееглубоко.Монады - это способ скрыть прохождение всего этого состояния.Это упрощенно, я знаю, но это заставляет тебя начать.Чтобы узнать больше о монадах и состоянии обработки, перейдите по этой ссылке: http://www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm

0 голосов
/ 14 сентября 2010

Возможно, вы также захотите проверить пакет простого наблюдателя на Hackage.(Раскрытие: я сопровождающий пакета.)

Это реализация Haskell шаблона проектирования Observer (просто билет для решения проблем «каждый раз что-то меняй ...» в рамках на основе событий), используя MVars для изменяемого состояния.Здесь есть пост в блоге, где обсуждается этот вопрос здесь

Я создал этот пакет, когда столкнулся с точно такой же проблемой, что и вы.

...