Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何减少Haskell中必须传递的参数数量?_Haskell_Gtk_Glade - Fatal编程技术网

如何减少Haskell中必须传递的参数数量?

如何减少Haskell中必须传递的参数数量?,haskell,gtk,glade,Haskell,Gtk,Glade,我在Haskell中的学习速度非常缓慢,试图让gui工具Git可用,等等。我遵循了使用glade创建简单gui应用程序的基本教程,现在我正在尝试将其模块化。特别是,我想利用函数,而不是在主目录中做所有事情。我做的第一件事是创建单独的函数来访问按钮,并将按钮单击时要执行的代码关联起来。它工作得很好,但是如果你看下面的代码,我必须随身携带整个GladeXML“变量”。我意识到我们在Haskell中不做全局的,但在我看来,必须有一个更好的机制,而不是在函数中携带每一个变量。显然,在OO世界中,XML内

我在Haskell中的学习速度非常缓慢,试图让gui工具Git可用,等等。我遵循了使用glade创建简单gui应用程序的基本教程,现在我正在尝试将其模块化。特别是,我想利用函数,而不是在主目录中做所有事情。我做的第一件事是创建单独的函数来访问按钮,并将按钮单击时要执行的代码关联起来。它工作得很好,但是如果你看下面的代码,我必须随身携带整个GladeXML“变量”。我意识到我们在Haskell中不做全局的,但在我看来,必须有一个更好的机制,而不是在函数中携带每一个变量。显然,在OO世界中,XML内容只是类中的一个实例变量,因此在任何地方都隐式可用。在哈斯克尔的世界里,什么是“正确”的方法

  module Main (main) where

  import Graphics.UI.Gtk
  import Graphics.UI.Gtk.Glade


  getButton :: GladeXML -> String -> IO Button
  getButton  gladeXML buttonName = 
      xmlGetWidget gladeXML castToButton buttonName



  onButtonClick :: GladeXML -> String -> [IO a] -> IO ()
  onButtonClick gladeXML buttonName codeSequence = do
      aButton <- getButton gladeXML buttonName
      _ <- onClicked aButton $ do   -- Run the sequence of operations when user clicks
         sequence_ codeSequence

      return ()

  loadGladeFile :: FilePath -> IO (Maybe GladeXML)
  loadGladeFile filename = do
      g <- xmlNew filename
      return g


  main :: IO ()
  main = do
      _ <- initGUI   -- Setup


      -- Load the Glade XML file
      Just xml <- loadGladeFile "tutorial.glade"


      -- Create main window (everything inside will be created too)
      window   <- xmlGetWidget xml castToWindow "window1"


      -- Define what to do when we quit
      _ <- onDestroy window mainQuit


      -- Show the wondow
      widgetShowAll window

      -- Associate an onClick event with a button
      onButtonClick xml "button1" [putStrLn "Hello, world"]

      -- Off we go
      mainGUI
主模块(Main),其中
导入Graphics.UI.Gtk
导入Graphics.UI.Gtk.Glade
getButton::GladeXML->String->IO按钮
getButton gladeXML buttonName=
xmlGetWidget gladeXML castToButton按钮名称
onButtonClick::GladeXML->String->[IO a]->IO()
onButtonClick gladeXML buttonName codeSequence=do

aButton这确实是augustss评论中的建议。完全未经测试,但这将让您开始:

import Control.Applicative
import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.Reader

import Graphics.UI.Gtk
import Graphics.UI.Gtk.Glade


getButton :: String -> ReaderT GladeXML IO Button
getButton buttonName = 
    do gladeXML <- ask
       return . lift $ xmlGetWidget gladeXML castToButton buttonName
试着阅读上面的文档和一些monad transformer教程


让我再试一次。我所做的是将两个可以单独处理的想法结合起来,然后再组合起来:

  • Reader
    monad
  • 单子变压器
  • 您可以从阅读这些内容开始,尝试理解
    阅读器
    单子:

    • );关注关于
      读者的部分(“未来价值的世界”)
    基本上,
    Reader
    是一个monad,它构造的值依赖于缺少的隐式“环境”值。在
    Reader
    monad中有一个名为
    ask::Reader r
    的操作,其结果是环境值

    因此,我们的想法是,无论您在哪里拥有
    GladeXML->something
    ,您都可以将该函数重写为
    Reader GladeXML something
    类型的一元操作。例如,上面我的示例的简化(没有monad transformer):

    然而,由于您在这里同时使用
    Reader
    IO
    ,因此您要做的是制作一个具有这两种功能的组合单子。这就是《蒙纳德变形金刚》为这幅画增添的色彩。
    ReaderT GladeXML IO A
    在概念上是一个
    IO
    操作,可以访问“隐式”GladeXML值:

    getButton :: String -> ReaderT GladeXML IO Button
    getButton buttonName = 
        do gladeXML <- ask
    
           -- There is one catch: to use any IO action, you have to prefix it with
           -- the `lift` function...
           button <- lift $ xmlGetWidget gladeXML castToButton buttonName
           return button
    
    -- I've refactored this slightly to *not* take a list of actions.
    onButtonClick :: String -> ReaderT GladeXML IO a -> ReaderT GladeXML IO ()
    onButtonClick gladeXML buttonName action = do
        aButton <- getButton buttonName
        xml <- ask
        _ <- lift $ onClicked aButton (runReaderT action xml)
        return ()
    
    
    -- This is the piece of code that illustrates the payoff of the refactoring.
    -- Note how there is no variable being passed around for the xml.  This is
    -- because I'm making a "big" ReaderT action out of small ones, and they will
    -- all implicitly get the same `GladeXML` value threaded through them.
    makeButton1 :: ReaderT GladeXML IO Button
    makeButton1 = 
        do button1 <- getButton "button1"
           onButtonClick "button1" $ do
               lift $ putStrLn "Hello, world"
           return button1
    
    -- The `main` action just fetches the `GladeXML` value and hands it off to the
    -- actual main logic, which is a `ReaderT` that expects that `GladeXML`
    main :: IO ()
    main = do
        xml <- ...
        runReaderT actualMain xml 
    
    actualMain :: ReaderT GladeXML IO ()
    actualMain = do ...
    
    getButton::String->ReaderT GladeXML IO按钮
    getButton按钮名称=
    
    使用gladeXML,您可以将所需的所有内容粘贴到一个记录中,并将其传递给其他人。或者使用读卡器monad来避免传递这些信息。@David如果你真的使用了唱片,你可能会想让Jon Sterling的乙烯基唱片旋转一下()。我自己还没有试过,但我听说它们解决了记录的名称空间问题(),我仍在努力了解基本知识。到目前为止,我最大的问题是,历史上对我来说微不足道的东西(使用德尔福、C++、Python、Objto-C、SimalTalk等语言)在Haskell中实现起来似乎非常复杂。当我开始从概念上理解这个读者Monad的情况时,它似乎是解决一个非常简单问题的一个非常复杂的方法。绕过函数式编程的“纯粹性”所需要的机制是非常复杂的。如果我理解了这一点,我相信我会立即给你的答案打上正确的标记。我还不够好,不能直接从文档中理解这些东西。我发现这些文档非常需要一个已经成为专家的人。我将尝试查找一些关于该读者的教程。感谢您花时间回复。如何调用getButton(say)函数?我的困难(我打赌其他人也有同样的困难)在于,库和文档通常定义了这些东西,但实际上并没有向您展示如何实际使用它们。这从一开始就是我的主要问题。@David我已经扩展了答案。看看这是否有帮助。恐怕我做的每件事都有点匆忙。还可以为
    ReaderT GladeXML IO
    使用类型别名,使类型签名更具可读性。
    getButton :: String -> Reader GladeXML (IO Button)
    getButton buttonName = do 
        -- The variable gladeXML gets the value of the "implicit" GladeXML value
        gladeXML <- ask 
    
        -- Now we use that value as an argument to the xmlGetWidget function.
        return $ xmlGetWidget gladeXML castToButton buttonName
    
    {- NOTE: none of this is guaranteed to even compile... -}
    
    example :: IO Button
    example = do 
        _ <- initGUI   -- Setup
        Just xml <- loadGladeFile "tutorial.glade"
        runReader (getButton "button1") xml
    
    getButton :: String -> ReaderT GladeXML IO Button
    getButton buttonName = 
        do gladeXML <- ask
    
           -- There is one catch: to use any IO action, you have to prefix it with
           -- the `lift` function...
           button <- lift $ xmlGetWidget gladeXML castToButton buttonName
           return button
    
    -- I've refactored this slightly to *not* take a list of actions.
    onButtonClick :: String -> ReaderT GladeXML IO a -> ReaderT GladeXML IO ()
    onButtonClick gladeXML buttonName action = do
        aButton <- getButton buttonName
        xml <- ask
        _ <- lift $ onClicked aButton (runReaderT action xml)
        return ()
    
    
    -- This is the piece of code that illustrates the payoff of the refactoring.
    -- Note how there is no variable being passed around for the xml.  This is
    -- because I'm making a "big" ReaderT action out of small ones, and they will
    -- all implicitly get the same `GladeXML` value threaded through them.
    makeButton1 :: ReaderT GladeXML IO Button
    makeButton1 = 
        do button1 <- getButton "button1"
           onButtonClick "button1" $ do
               lift $ putStrLn "Hello, world"
           return button1
    
    -- The `main` action just fetches the `GladeXML` value and hands it off to the
    -- actual main logic, which is a `ReaderT` that expects that `GladeXML`
    main :: IO ()
    main = do
        xml <- ...
        runReaderT actualMain xml 
    
    actualMain :: ReaderT GladeXML IO ()
    actualMain = do ...