Haskell - 将变量传递给子函数

时间:2011-05-10 16:24:13

标签: haskell

我有一个函数main,它有一个子函数menu。在main中,我加载文件,要求用户输入其名称,然后调用menu以显示菜单。菜单中的每个操作完成后,我将再次调用menu,直到满足退出条件。

我在将main中加载的文件传递给menu时遇到问题 - 我想对每个命令执行数据库操作。

这是我的代码到目前为止(我已经删除了无关的位):

main :: IO ()
main = do contents <- readFile "myfile.txt"
          let finalDatabase = (read contents :: [Film])
          putStr "Please enter your name: "
          name <- getLine
          menu finalDatabase
          where menu db = do putStrLn "Please select an option:"
                             putStrLn "1: Display all films"
                             putStr "Choice: "
                             choice <- getLine
                             case choice of {
                                 "1" -> displayAll db;
                             }
                             menu

displayAll函数可以很好地打印出数据库。

我在WinHugs中遇到以下错误:

ERROR file:.\films.hs:152 - Type error in function binding
*** Term           : menu
*** Type           : [([Char],[[Char]],Int,[[Char]])] -> IO a
*** Does not match : IO a

我认为如果我没有指定像menu :: Database -> IO ()这样的行,它会接受任何参数而不关心它们的类型。

有什么建议吗?

修改: 愚蠢的错误,我只是在案例陈述后再次调用菜单时忘了传递数据库!

2 个答案:

答案 0 :(得分:1)

  

我认为如果我没有指定像menu :: Database -> IO ()这样的行,它会接受任何参数而不关心它们的类型。

这不是真的,在你的情况下menu确实有类型Database -> IO ()所以在where之前的最后一行,你需要给它一个Database来获取一个IO () - 可能是db(如menu db中所示),但也许稍后,您将开始修改数据库,然后您可以传入新数据库.Haskell不只是环顾四周在什么范围内找到Database类型的合适值!

如果数据库确实已修复,则无需传入,您可以使用以下内容:

main = do contents <- readFile "myfile.txt"
       let finalDatabase = (read contents :: [Film])
       putStr "Please enter your name: "
       name <- getLine
       menu
       where menu = do putStrLn "Please select an option:"
                       putStrLn "1: Display all films"
                       putStr "Choice: "
                       choice <- getLine
                       case choice of {
                           "1" -> displayAll finalDatabase -- instead of db
                       }
                       menu

但是,正如所说,当你开始修改'数据库'时,这将会破裂。假设您定义了一个函数doSomethingWithDatabaseDependingOnChoice :: String -> [Film] -> IO [Film],它接受​​选择和旧数据库,执行一些输入/输出并返回一个新数据库,您可以按如下方式使用它:

      <same as before>
      menu finalDatabase
      where menu db = do putStrLn "Please select an option:"
                         putStrLn "1: Display all films"
                         putStr "Choice: "
                         choice <- getLine
                         newDb <- doSomethingWithDatabaseDependingOnChoice choice db
                         menu newDb

另一种选择是使用隐式参数,但我猜这一点有点太高级了!

答案 1 :(得分:0)

首先,不,不指定类型,并不意味着该函数将随时接受。这意味着将推断出类型。

您获得该特定类型错误的原因是,在menu的{​​{1}}块结束时,您编写do,这是一个函数而不是值类型为menu。我不确定你为什么那样做。如果要创建无限循环,则应将最后一次调用更改为IO,而不是返回未应用的函数。如果你不想要无限循环,我不明白为什么你最后会使用menu db