【问题标题】:Haskell: Do block, last statement must be expressionHaskell:做块,最后一条语句必须是表达式
【发布时间】:2015-01-05 15:42:40
【问题描述】:

我想知道右击或左击按钮的区别。我写了以下代码:

import Graphics.UI.Gtk
import Control.Monad.IO.Class 

--main::IO()
main = do
    initGUI

window <- windowNew

    button <- buttonNewWithLabel "button"

    on button buttonPressEvent (tryEvent (do button <- eventButton

                                             liftIO (extrafunctie button)
                                             ))                                         
    containerAdd window button

    onDestroy window mainQuit

    widgetShowAll window

    mainGUI

extrafunctie b = if (RightButton == b) 
                 then putStrLn "True"
                 else putStrLn "False"

我收到以下错误:

jolien@jolien-VirtualBox:~/Documenten/haskell$ ghc --make test.hs -o test
[1 of 1] Compiling Main             ( test.hs, test.o )

test.hs:9:50:
    The last statement in a 'do' block must be an expression
      button <- eventButton liftIO (extrafunctie button)

我查看了我的缩进,这是正确的。有人知道解决方案吗?

【问题讨论】:

  • 这看起来确实像一个缩进问题。你检查过制表符吗? IIRC Haskell 将它们解释为“标签到下一个 8 个空格的倍数”,也许您的编辑器会有所不同。
  • button &lt;- eventButton;:D
  • 使用ghc 进行检查,就缩进而言,您在此处粘贴的代码似乎没问题,因此可能有一些不可见的字符和/或像@Tarmil 建议的标签。我怀疑代码没有正确粘贴到问题中。
  • 仅供参考 StackOverflow 引擎在将 MarkDown 源呈现为 HTML 时会将制表符转换为四个空格,但是当您单击“编辑”并查看原始源时,那里有制表符。
  • @JoJoD 它之所以有效,是因为缩进是一种隐含的{;},如果你愿意,你可以明确地给出它们。问题是缩进,如果您将编辑器的制表位设置为 8,或者将所有制表符替换为空格,您就可以看到它。见stackoverflow.com/a/27714157/1598537

标签: haskell expression


【解决方案1】:

你的缩进很糟糕,这就是问题所在。你需要替换这个:

on button buttonPressEvent (tryEvent (do button <- eventButton

                                         liftIO (extrafunctie button)
                                         ))  

与:

on button buttonPressEvent $
    tryEvent $ do 
        button <- eventButton
        liftIO (extrafunctie button)

您还可以将 extrafunctie 函数替换为:

extrafunctie b = print (RightButton == b)

【讨论】:

    【解决方案2】:

    以下是编译器如何看待您的代码,制表位的间隔为 8 个字符。 我将标签显示为-------|,空格显示为.

    >....import Graphics.UI.Gtk
    >....import Control.Monad.IO.Class 
    >
    >....--main::IO()
    >....main = do
    >....-|initGUI
    
    >...--|window <- windowNew
    
    >....-|button <- buttonNewWithLabel "button"
    
    >....-|on button buttonPressEvent (tryEvent (do button <- eventButton
    
    >....-|------|------|------|------|------|------|------|------|------|..----|.liftIO (extrafunctie button)
    >....-|------|------|------|------|------|------|------|------|------|.....))                                           
    >....-|containerAdd window button
    
    >....-|onDestroy window mainQuit
    
    >....-|widgetShowAll window
    
    >....-|mainGUI
    >
    >....extrafunctie b = if (RightButton == b) 
    >....-|------|------|------|.then putStrLn "True"
    >....-|------|------|------|.else putStrLn "False"
    

    如您所见,编译器在右侧看到liftIO (extrafunctie 位。 如果您使用空间来布置您的工作,这不会发生:

    >    import Graphics.UI.Gtk
    >    import Control.Monad.IO.Class 
    >
    >    --main::IO()
    >    main = do
    >      initGUI
    >      window <- windowNew
    >      button <- buttonNewWithLabel "button"
    >      on button buttonPressEvent (tryEvent (do button <- eventButton
    >                                               liftIO (extrafunctie button)
    >                                               ))                                             
    >      containerAdd window button
    >      onDestroy window mainQuit
    >      widgetShowAll window
    >      mainGUI
    >
    >    extrafunctie b = if (RightButton == b) 
    >                  then putStrLn "True"
    >                  else putStrLn "False"
    

    如果你坚持使用空格,那是最简单的。更改编辑器的设置。

    如果你只使用空格而不使用任何制表符,你就不会遇到这个问题,因为你的编辑器必须按照编译器的想法来显示它。

    我的编辑器让我指定当我按下制表符时,它应该插入制表符显示的空格数,所以我使用它,这对于 4 制表位是安全的。如果您的编辑器可以这样做,请使用该选项。 (如果没有,请考虑在编程时使用更聪明的编辑器。)

    我的编辑器也有自动缩进和outdent,下一行复制上一行的空白缩进——这避免了这个问题。如果您的编辑器支持它,请打开它,因为它可以节省您的精力并且您不太可能遇到解析错误。 (当我按下退格键时,我的编辑器会删除回上一级缩进,这很好。)

    几乎所有编辑器都可以更改标签的显示方式。如果你不能让它为制表符使用空格,你应该将制表位更改为 8,因为这与 ghc 匹配,并且你不太可能得到这个错误,但你最好还是使用空格。

    【讨论】:

      【解决方案3】:

      接下来怎么样?

      import Graphics.UI.Gtk
      import Control.Monad.IO.Class 
      
      --main::IO()
      main = do
        initGUI
        window <- windowNew
        button <- buttonNewWithLabel "button"
        on button buttonPressEvent (tryEvent (do button <- eventButton
                                               liftIO (extrafunctie button)
                                               ))                                      
        containerAdd window button
        onDestroy window mainQuit
        widgetShowAll window
        mainGUI
      
      extrafunctie b = if (RightButton == b) 
                 then putStrLn "True"
                 else putStrLn "False"
      

      【讨论】:

      • 不好,因为额外功能在主函数中 ==> 不能这样做(解析错误 =)
      • 认为我的缩进会有所作为。期待答案。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多