3

每次用户与我的程序交互时,我都很难找出如何进行更改。很难解释,所以这里有一个例子(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

4 回答 4

5

函数的参数是你的变量。当用户输入新值时,将这些值传递给函数。

例如,一个根据用户输入更新值的简单程序:

main = loop 0

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

请注意,根据用户提供的内容,对“循环”的递归调用每次都传递不同的值。

这是函数式编程中的一种基本思维方式——命令式程序中循环中的局部可变变量将成为函数式程序中递归函数的参数。

于 2010-07-24T18:47:15.633 回答
2

不幸的是,由于 wxHaskell 是一个基于事件的框架,Don 和 ZachS 的答案并不适用。

您在这里要做的是分配一个可变变量,就像在命令式语言中一样。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)和状态单子。

于 2010-07-28T13:56:39.047 回答
1

在函数式语言中执行此操作的一种方法是通过函数将您的状态线程化。某些功能可能由 monad 处理,例如获取键盘状态,因此您不必自己处理。一个例子(或多或少的伪代码):

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

这应该让您了解如何开始。

编辑:

我应该更深入地提到 Monads。Monads 基本上是一种隐藏所有状态传递的方法。我知道,它过于简单化了,但它可以帮助您入门。要阅读有关 monad 和处理状态的更多信息,请点击此链接:http ://www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm

于 2010-07-24T18:41:25.490 回答
0

您可能还想查看 Hackage 上的 simple-observer 包。(披露:我是包维护者。)

它是 Observer 设计模式的 Haskell 实现(只是在基于事件的框架中解决“每次都做出改变……”问题的门票),使用 MVars 来实现可变状态。有一篇博文在这里进一步讨论

当我遇到与您完全相同的问题时,我创建了这个包。

于 2010-09-14T15:56:04.727 回答