haskell - 在 Haskell 中使用 do 语句
问题描述
终于学会了如何在 Haskell 中使用 monad!
我想读取一个文件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
失败,因为您试图tail
在IO [String]
. 你需要fmap
的tail
功能:
contents <- fmap tail . fmap lines . readFile $ "testInput"
-- or....
contents <- fmap (tail . lines) . readFile $ "testInput"
现在您需要一种方法从contents
. 您可以为此定义一个简单的everyOther
函数:
everyOther :: [a] -> [a]
everyOther (x:_:xs) = x : everyOther xs
everyOther _ = []
现在您可以将其链接到您fmap
的第一行:
contents <- fmap (everyOther . tail . lines) . readFile $ "testInput"
您的waffles
功能(row - 1)*(col - 1)
似乎与我认为的类型签名无关。尝试从类型签名开始并waffles
从中构建。根据您的描述,您只是向函数提供每隔一行,因此它应该具有签名:
waffles :: String -> String
鉴于 的类型签名waffles
,您可以通过以下方式应用它:
let result = fmap waffles contents
输出的另一件事:concat
将所有行混合在一起。您可能希望在其中换行,因此您可能想要使用unlines
。
main = do
contents <- fmap (everyOther . tail . lines) . readFile $ "testInput"
let result = fmap waffles contents
writeFile "output.txt" $ unlines result
推荐阅读
- date - Racket:在合同中使用的自定义谓词
- sql - 使用自联接运行总计
- exchangewebservices - EWS API:如何检索附件的修改日期
- ruby-on-rails - 从 json 中获取数字最小的 .each 循环结果
- python - trans_primitives 不会生成到 datetime 列
- oauth-2.0 - 将 Oauth 2.0 与 Next js 一起使用
- python - 如何使用 Matplotlib 缩放体素维度?
- avr - 如何在 oled 显示器上显示 uint8 值
- ansible - 如何按顺序在主机上进行ansible循环
- mysql - MySql 8.0.0 和 Docker 组合问题