2014-02-26 56 views
1

我試着去實現這個概念的IO代碼:哈斯克爾實現一個IO碼

  • 要求用戶爲電影標題
  • 檢查,如果電影的存在,如果沒有則返回到主菜單
  • 如果它的方案詢問評級
  • 它檢查如果有效的整數,如果它
  • 程序檢查用戶是否已經投票支持這部電影的用戶
  • 如果他不那麼問他是否要修改的評價
  • 如果用戶輸入其不等於「Y」,那麼該程序應該返回到主菜單
  • 如果用戶輸入「Y」則數據庫應該用當前的更新進行更新。

我嘗試這樣做:

if input /= "y" 
    then do return (username, database) 
    else do putStrLn "Your vote will be modified." 

,但我得到這個錯誤:

Couldn't match expected type `()' 
       with actual type `(String, Database)' 
    In the first argument of `return', namely `(username, database)' 
    In a stmt of a 'do' block: return (username, database) 
    In the expression: do { return (username, database) } 
Failed, modules loaded: none. 

如果這樣運行:

if input /= "y" 
    then do return (username, database) 
    else do putStrLn "Your vote will be modified." 

即使用戶的輸入不等於「y」數據庫將被更新。 我無法揣摩出與回報(用戶名,數據庫)的問題

的代碼是:

options 7 (username, database) = do 
    putStrLn "******************" 
    putStrLn " Rate a film " 
    putStrLn "******************" 
    putStrLn "" 
    putStr "Enter the title of the film or nothing to return to the main menu: " 
    title <- getLine 
    if title == "" 
     then return(username, database) 
     else do 
      let filmCheck = findFilm title database 
      if filmCheck == [] 
       then do 
        putStrLn "That film does not exists." 
        return (username, database) 
       else do 
        putStr "Enter your rate: " 
        tempRate <- getLine 
        case reads tempRate :: [(Integer, String)] of 
         [(n, "")] -> do 
          let rate = read tempRate :: Int 
          let tempFilm = rateFilm username (username, rate) filmCheck 
          when (checkIfRated username tempFilm == True) $ do 
           putStrLn "You already voted for this film\n" 
           putStrLn "Do you want to modify your vote?\n" 
           putStrLn "Press y to modify or nothing to return to the main menu:" 
           input <- getLine 
           if input /= "y" 
            then do return (username, database) 
            else do putStrLn "Your vote will be modified." 
          let database = tempFilm:database 
          putStrLn "You rating has been sumbited successfully!" 
          putStrLn (displayFilm tempFilm) 
          return (username, database) 
         _ -> do 
          putStrLn "The number you entered is invalid." 
          return (username, database) 
+0

你是否期待'return(username,database)'退出函數?它所做的只是在monadic上下文中包含一個值,代碼爲'f = do {return「hello」;迴歸「世界」;返回1; putStrLn「返回1」; return 2}'將返回'2',因爲這是在該塊中執行的最後一條語句。其他'返回'只是正常的函數調用。 – bheklilr

+2

我發現的另一個錯誤,'let database = tempFilm:database'將無法按預期工作。它不會將「數據庫」值重新綁定到新數據庫。相反,你正在爲'database'定義一個遞歸綁定,這個綁定可以擴展成相當於'repeat tempFilm'。相反,你應該做一些像'let newDatabase = tempFilm:database',然後做'return(username,newDatabase)'。 – bheklilr

+0

這正是我想要做的。而不是返回如何強制haskell退出函數?有什麼辦法嗎? 並感謝發現的錯誤。 – Bobys

回答

4

首先,你的縮進是靠不住的。請記住,縮進在Haskell中很重要;如果你弄錯了,你的改變了代碼的含義

乍一看,我認爲這個問題是在這裏:

if input /= "y" 
    then do return (username, database) 
    else do putStrLn "Your vote iwll be modified." 

的「做」關鍵字實際上是多餘的位置。但更重要的是,putStrLn返回(),而return明確返回其他內容。有你的錯誤。

另一方面,嘗試將其分解,方法更小的功能。這不是Java ...

+3

我認爲真正的問題是'return'不能退出函數,它只是包裝一個monadic值。我的猜測是OP假設'return'是一個關鍵字,與其他許多語言一樣,它實際上會強制函數以給定的值退出,但在Haskell中,它只是一個函數,用於將值包裝到monad中。 – bheklilr

+0

@bheklilr你可能是對的。我看到幾個分支_end_和一個'return',看起來合法。但是,如果阻止在中間?這個_does_看起來有點嫌疑,現在你提到它... – MathematicalOrchid

+1

我設法通過簡化我的編碼並只使用較不復雜的if語句來獲得我想要的結果。謝謝你們! – Bobys