【问题标题】:Haskell Implement an IO codeHaskell 实现一个 IO 代码
【发布时间】:2014-03-30 00:10:52
【问题描述】:

我正在尝试用这个概念实现一个 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)

【问题讨论】:

  • 您是否希望return (username, database) 退出该功能?它所做的只是在单子上下文中包装一个值,代码f = do { return "hello"; return "world"; return 1; putStrLn "Returned 1"; return 2 } 将返回2,因为这是在该块中执行的最后一条语句。其他的returns 只是普通的函数调用。
  • 我发现的另一个错误,let database = tempFilm:database 不会像您预期的那样工作。它不会将database 值重新绑定到新值。相反,您正在为database 定义一个递归绑定,它将扩展为等效于repeat tempFilm。相反,您应该执行let newDatabase = tempFilm : database 之类的操作,然后执行return (username, newDatabase)
  • 这正是我想要做的。而不是 return 如何强制 haskell 退出函数?有什么办法吗?并感谢发现的错误。

标签: haskell


【解决方案1】:

首先,您的缩进很不稳定。请记住,缩进在 Haskell 中很重要。如果你弄错了,你改变代码的含义

乍一看,我认为问题出在这里:

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

“do”关键字在这里实际上是多余的。但更重要的是,putStrLn 返回 (),而 return 显然返回其他内容。这是你的错误。

另外,试着把它分解成更小的函数。这不是 Java...

【讨论】:

  • 我认为真正的问题是return 没有退出函数,它只是包装了一个单子值。我的猜测是,OP 假设 return 是许多其他语言中的关键字,并且它实际上强制函数以给定的值退出,但在 Haskell 中,它只是一个用于将值包装在 monad 中的函数。跨度>
  • @bheklilr 你可能是对的。我看到几个分支end 带有return,看起来是合法的。但是那个if-block就在中间? 确实看起来有点可疑,既然你提到它......
  • 我设法通过简化我的编码并只使用不太复杂的 if 语句来获得我想要的结果。谢谢大家!
猜你喜欢
  • 2012-05-13
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-10-02
  • 2023-04-03
  • 1970-01-01
  • 2019-03-28
  • 1970-01-01
相关资源
最近更新 更多