【问题标题】:(Haskell) gi-gtk setting image in button callback(Haskell) gi-gtk 在按钮回调中设置图像
【发布时间】:2021-06-26 14:58:07
【问题描述】:

我遵循了有关创建基本 Gi-Gtk 应用程序的教程。 现在我想通过将图像的源设置为我从常量字符串列表中随机选择的字符串来响应按钮按下:

{-# LANGUAGE OverloadedLabels #-}
{-# LANGUAGE OverloadedStrings #-}
module Main where

import Data.GI.Base
import System.Random 
import qualified GI.Gtk as Gtk
import Control.Monad.Random

akkorde = ["C11.png","C13.png","C69.png","C6.png","C7#11.png","C7#9.png","C7b13.png","C7b9.png","C7.png","C9.png","Cadd9.png","Cj7.png"]

selectAcc:: (MonadRandom m) => m [Char]
selectAcc = do 
  let n = length akkorde  
  i <- getRandomR (0, n-1)
  return (akkorde !! i)
main :: IO ()
main = do 
  name <- selectAcc
  Gtk.init Nothing
  win <- Gtk.windowNew Gtk.WindowTypeToplevel
  Gtk.windowSetTitle win "accordtrainer"
  Gtk.onWidgetDestroy win Gtk.mainQuit
  #resize win 640 480
  
  img <- Gtk.imageNewFromFile ("../" ++ name)   
  box <- new Gtk.Box [#orientation := Gtk.OrientationVertical ]
  #add box img
  #add win box
    
  msg <- new Gtk.Label[#label := ( "")]
  #packStart box msg True False 10
 
  btn <- new Gtk.Button [#label := "Click me!"]
  #packStart box btn False False 10
  on btn #clicked ( Gtk.imageSetFromFile img  (do { name <- selectAcc; return ("../" ++ name) }))
  Gtk.widgetShowAll win
  Gtk.main

问题出现在生产线上

  on btn #clicked ( Gtk.imageSetFromFile img  (do { name <- selectAcc; return ("../" ++ name) }))

我认为 Gtk.imageSetFromFile 需要一个 Maybe[Char] 但目前它只得到 [Char] ghc 说:

app/Main.hs:38:62: error:
    • No instance for (MonadRandom Maybe)
        arising from a use of ‘selectAcc’

Just 构造函数应该给我一个可能的类型

  on btn #clicked ( Gtk.imageSetFromFile img  (Just(do { name <- selectAcc; return ("../" ++ name) })))

然后我得到一个类型不匹配

• Couldn't match type ‘[Char]’ with ‘Char’
  Expected type: Maybe [Char]
    Actual type: Maybe [[Char]]

错误/“修复”链继续

我认为我做的事情根本上是错误的,但我不知道如何以“正确”的方式执行此操作,如果您知道我应该如何编写此行或获取随机选择的字符串的更好方法,请回复

【问题讨论】:

  • Haskell 可能是一门难学的语言,而 monad 无疑是一个微妙的概念——我们都在学习,没有必要难过。

标签: haskell random callback gtk monads


【解决方案1】:

您已经在使用mtl 样式的 monad 约束,它比普通的 monad 更高级,所以不用担心无法理解所有内容。

imageSetFromFile 的简化类型为:

imageSetFromFile :: Image -> Maybe [Char] -> IO ()

因此它希望您提供Maybe [Char] 作为输入,其中Nothing 可能会删除图像,Just someFile 会将图像设置到该文件位置。

您正在使用的函数具有以下类型:

selectAcc:: MonadRandom m => m [Char]

这意味着这里的m 需要是一些可以生成随机数的monad。您可以通过在 GHCi 中键入以下内容来找到 MonadRandom 的实例:

ghci> import Control.Monad.Random
ghci> :i MonadRandom
type MonadRandom :: (* -> *) -> Constraint
class Monad m => MonadRandom m where
  getRandomR :: Random a => (a, a) -> m a
  getRandom :: Random a => m a
  getRandomRs :: Random a => (a, a) -> m [a]
  getRandoms :: Random a => m [a]
  {-# MINIMAL getRandomR, getRandom, getRandomRs, getRandoms #-}
    -- Defined in ‘Control.Monad.Random.Class’
instance (RandomGen g, Monad m) => MonadRandom (RandT g m)
  -- Defined in ‘Control.Monad.Trans.Random.Lazy’
instance [safe] MonadRandom IO
  -- Defined in ‘Control.Monad.Random.Class’

在底部,您会看到两个实例:RandT(monad 转换器)和IO。但是,imageSetFromFile 需要 Maybe [Char] 作为参数,因此两者都不会立即起作用。但是在这种情况下,您可以在 imageSetFromFile 调用 IO monad 之前生成随机名称:

  on btn #clicked $ do
    name <- selectAcc
    Gtk.imageSetFromFile img (Just ("../" ++ name))

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 2022-07-15
    • 2018-11-02
    • 2014-03-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多