为了尝试将Haskell用于图形应用程序,我在使用GUI进行评估时遇到了很多麻烦。
例如,我有时会尝试在程序中的某个位置创建小部件,打包并将其发送到程序的其他组件。
这样做效果不好,通常永远不会导致窗口小部件显示,因为懒惰的评估会在窗口小部件被放到屏幕上之前丢弃窗口小部件。
所以我想知道,除了投入一堆seq
和其他变体以鼓励急切评估之外,可以/如何处理这个问题?
我已经找到了答案,但无法找到任何与此问题相关的内容。
编辑:示例代码
下面的代码产生了一个空窗口。
{-# LANGUAGE RecursiveDo #-}
-- allows recursive do notation
-- mdo
-- ...
import Control.Monad
import Control.Monad.IO.Class
import qualified Data.Map.Strict as Map
import qualified Data.List as List
import System.Random
import Graphics.UI.WX hiding (Event)
import Graphics.UI.WXCore as WXCore
import Reactive.Banana
import Reactive.Banana.WX
boardWidth, boardHeight :: Int
boardWidth = 41
boardHeight = 81
main :: IO ()
main = start tetris
tetris = do
ff <- frame [text := "Tetris"
,bgcolor := white
,resizeable:= False]
p <- panel ff []
set ff [ layout := minsize (sz 100 100) $ widget p]
pps <- return $ Map.fromList $ map (\l@(x,y) -> (l, button p []))
[(x,y) | x <- [1..(boardWidth `div` 2)], y <- [1..(boardHeight `div` 2)]]
-- p <- pps Map.! (1,2)
d <- return $ map (\(x,y_m) -> y_m >>= (\y -> set ff [ color := white, layout := minsize (sz 300 300) $ widget y ])) $ Map.toList pps
-- let networkDescription :: Moment IO ()
return ff
线p <- pps Map.! (1,2)
导致图块显示为1,2,没有正确的尺寸。
答案 0 :(得分:1)
这并不能很好地解决这个问题,通常永远不会导致窗口小部件显示,因为懒惰的评估在它有机会被放到屏幕上之前丢弃了窗口小部件。
正如Thomas M. DuBuisson所说,这是一种误诊:这里的问题与懒惰的评估无关(在任何情况下,懒惰的评估都不会丢弃你实际尝试使用的值) 。让我们来看看您应该将按钮添加到面板的行:
d <- return $ map (\(x,y_m) ->
y_m >>= (\y -> set ff [ color := white, layout := minsize (sz 300 300) $ widget y ]))
$ Map.toList pps
Map.toList pps
的类型为[((Int, Int), IO (Button ())]
。您对map
的使用会将其更改为[IO ()]
(参见the type of set
), IO
次操作列表。实际上,您正在设置添加按钮的操作,但实际上从未实际运行它们。为此,您需要traverse_
而不是Data.Foldable
的{{1}}:
map
(有关traverse_ (\(x,y_m) ->
y_m >>= (\y -> set ff [ color := white, layout := minsize (sz 300 300) $ widget y ]))
$ Map.toList pps
及其堂兄traverse_
的更多信息,请参阅this answer,以及其他父母问题的答案。)
请注意,除非我严重误读特定于WX的代码,否则仍然无法完成您想要的。当您为列表元素生成的每个traverse
操作重置框架的布局时,您最终只会使用框架中的最后一个按钮。为了获得合理的布局,您必须实际使用坐标值,以及WX布局组合器以使用所有按钮设置单个布局。参看the Graphics.UI.WX.Layout
documentation
最后一点,在do-block中这样的代码......
IO
...总是多余的:它可以替换为:
bar <- return foo
在你的情况下,这样做会更明显地表明你并没有真正运行这些行动。
(您对let bar = foo
和Map.fromList
的使用也是多余的,但我猜您已经怀疑过了。)