在Haskell中使用do语句

在Haskell中使用do语句,haskell,io,monads,Haskell,Io,Monads,终于学会如何在Haskell中使用单子了 我想读取一个文件testInput,删除第一行,每隔一行应用函数waffles,并将结果保存在文件output.txt中 我编写了以下代码: main = do contents <- tail . fmap lines . readFile $ "testInput" result <- fmap waffles contents writeFile "output.txt" $ concat result waf

终于学会如何在Haskell中使用单子了

我想读取一个文件testInput,删除第一行,每隔一行应用函数waffles,并将结果保存在文件output.txt中

我编写了以下代码:

main = do
    contents <- tail . fmap lines . readFile $ "testInput"
    result <- fmap waffles contents
    writeFile "output.txt" $ concat result

waffles row col = (row - 1)*(col - 1)
遗憾的是,编译器抱怨:

waffles.hs:3:41:
    Couldn't match type ‘IO String’ with ‘[String]’
    Expected type: FilePath -> [String]
      Actual type: FilePath -> IO String
    In the second argument of ‘(.)’, namely ‘readFile’
    In the second argument of ‘(.)’, namely ‘fmap lines . readFile’

waffles.hs:5:9:
    Couldn't match expected type ‘[b]’ with actual type ‘IO ()’
    Relevant bindings include program :: [b] (bound at waffles.hs:2:1)
    In a stmt of a 'do' block: writeFile "output.txt" $ concat result
    In the expression:
      do { contents <- tail . fmap lines . readFile $ "testInput";
           result <- fmap waffles contents;
           writeFile "output.txt" $ concat result }
    In an equation for ‘program’:
        program
          = do { contents <- tail . fmap lines . readFile $ "testInput";
                 result <- fmap waffles contents;
                 writeFile "output.txt" $ concat result }
Failed, modules loaded: none.
我觉得这个错误相当可怕。你能帮我调试一下吗

我也将感谢代码风格的建议

编辑:我忘了拆分文件的行并将它们转换为整数。我试着解决这个问题如下:

main = do
    contents <- tail . fmap lines . readFile $ "testInput"
    contents <- fmap read . words contents
    result <- fmap waffles contents
    writeFile "output.txt" $ concat result

waffles row col = (row - 1)*(col - 1)
但这只会引入更多令人困惑的编译器错误。

do语句中的第一行失败,因为您试图在IO[String]上使用tail。您需要fmap尾部功能:


内容我将为第一个错误提供一个提示:因为您使用fmap编写tail,编译器假定您的意思是fmap引用[]版本的fmap fmap行::[String]->[[String]],而不是IO的。很好!对于第二个错误,请思考您希望表达式fmap waffles contents中的内容类型。我希望Haskell有一个不错的交互式IDE,这样你就可以实时查看变量的类型了。@BenjaminHodgson ghci没有一个很好的方法来实现这一点。例如,这里如果I:set-fdefer-type-errors;:set+c;:l test.hs;:在test.hs 2 4 2 13中键入最后一个命令的格式:start line、start column、end line、end column I get::[String]。但它非常挑剔,似乎不能很好地与:r或更高版本的:l命令协调,而且必须在编辑器中进行修改才能获得行号和列号,这太糟糕了。:all-types命令明显更加冗长,交互性更低,但具有讽刺意味的是,它在某些方面更易使用…@DanielWagner整洁的技巧,但不是一个很好的UI!如果提问者能够悬停在一个标识符上并看到一个带有该类型的弹出窗口,他们可能已经能够解决他们自己的问题,甚至不需要来堆栈OverflowWell内容应该是IO字符串类型这里有几个错误。首先,您需要fmap的原因是readFile为您提供了一个IO字符串,即该字符串位于IO monad中。您无法从IO中取出字符串,但您可以进入IO内部,对其中的字符串执行操作,就像处理任何其他容器一样。fmap就是这个功能。我认为fmap是尾巴。fmap应该是fmap尾部。谢谢,DarthFennec。我纠正了错误
everyOther :: [a] -> [a]
everyOther (x:_:xs) = x : everyOther xs
everyOther _        = []
contents <- fmap (everyOther . tail . lines) . readFile $ "testInput"
waffles :: String -> String
let result = fmap waffles contents
main = do
    contents <- fmap (everyOther . tail . lines) . readFile $ "testInput"
    let result = fmap waffles contents
    writeFile "output.txt" $ unlines result