像命令式程序一样跟踪 Haskell 中的程序变量
每次用户与我的程序交互时,我很难找出如何进行更改。很难解释,所以这里有一个例子(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.
您如何以功能性方式解决此类问题?
I'm having a hard time finding out how to make something change every time the user interacts with my program. It's hard to explain so here's an example (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 ()
I want some widgets to change when the "Next Question" button is pressed. I want to change these widgets to some values I read from a file. How can I keep track of what the current question number is? I cannot actually increment questionNumber as a variable, since Haskell doesn't permit such things. I guess there's another way to do it.
Example:
Initialize GUI
Read data from file
If button is pressed, increment question number by 1 and change widgets.
How do you tackle this kind of problem in a functional manner?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
发布评论
评论(4)
不幸的是,由于 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)
和状态单子。
在函数式语言中实现此目的的一种方法是通过函数将状态线程化。某些功能可能由 monad 处理,例如获取键盘状态,因此您不必自己处理。一个示例(或多或少的伪代码):
someFunction :: SomeDataTypeThatRepresentsState -> a ... -> (SDTTRS, a...) (change to fit reality of course)
someFunction x y .... | x == WeHaveKeyboardInput = someFunction dowhatever.....
| someFunction dowhateverelse
这应该让您了解如何开始。
编辑:
我应该更深入地提到 Monad。 Monad 基本上是隐藏所有状态传递的一种方法。我知道它过于简单化了,但它可以让你开始。要了解有关 monad 和处理状态的更多信息,请点击以下链接:http:// www.engr.mun.ca/~theo/Misc/haskell_and_monads.htm
您可能还想查看 Hackage 上的 simple-observer 包。 (声明:我是包维护者。)
它是 Observer 设计模式的 Haskell 实现(只是在基于事件的框架中解决“每次都进行更改......”问题的门票),使用 MVar 来实现可变状态。 此处有一篇博客文章进一步讨论了该问题
当我遇到与你完全相同的问题时,我创建了这个包。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
函数的参数是变量。当用户输入新值时,将这些值传递给函数。
例如,一个根据用户输入更新值的简单程序:
请注意,根据用户提供的内容,对“loop”的递归调用每次都会传递不同的值。
这是函数式编程的基本思维方式——命令式程序中循环中的局部可变变量变成了函数式程序中递归函数的参数。
The arguments to functions are your variables. As the user enters new values, pass those values to functions.
For example, a simple program that updates a value based on user input:
Note the recursive calls to 'loop' have a different value passed each time, based on what the user provided.
This is a fundamental way of thinking in functional programming -- what would be a local, mutable variable in a loop in an imperative program becomes a parameter to a recursive function in a functional program.