haskell - do 块中的 Haskell 递归不起作用(递归在列表理解中)
问题描述
我对 Haskell 很陌生,想在 do 块中执行递归。
countLines :: String -> IO Int
countLines filePath = do
isFile <- doesFileExist filePath
if isFile
then do contents <- readFile filePath
print contents
pure 0
else do files <- getDirectoryContents filePath
[countLines(file) | file <- files] -- recursion here!
pure 0
在我添加这个列表理解之前,一切正常,但是一旦我添加这个,我得到以下错误:
Main.hs:59:17: error:
• Couldn't match type ‘[]’ with ‘IO’
Expected type: IO (IO Int)
Actual type: [IO Int]
• In a stmt of a 'do' block: [countLines (file) | file <- files]
In the expression:
do files <- getDirectoryContents filePath
[countLines (file) | file <- files]
pure 0
In a stmt of a 'do' block:
if isFile then
do contents <- readFile filePath
print contents
pure 0
else
do files <- getDirectoryContents filePath
[countLines (file) | file <- files]
pure 0
|
59 | [countLines(file) | file <- files]
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
bash-3.2$
有谁知道如何解决这一问题?
解决方案
列表推导是[IO Int]
, not的表达式IO Int
,虽然列表[]
是类型类的成员Monad
,但它不是您当前在do
块中使用的。您可以mapM_ :: (Foldable f, Monad m) => (a -> m b) -> f a -> m ()
在这里使用递归:
countLines :: String -> IO Int
countLines filePath = do
isFile <- doesFileExist filePath
if isFile
then readFile filePath >>= print
else getDirectoryContents filePath >>= mapM_ countLines
pure 0
正如@chi 所说,如果您需要检索结果列表,您应该使用mapM :: (Traversable f, Monad m) => (a -> m b) -> t a -> m (t b)
. 因此,您可以提供单子调用结果的列表。例如,您可以将这些相加以获得结果。我把它留作练习。
推荐阅读
- sql - SQL - 解析 JsonData 并制作表格数据
- html - 如何删除图像与其下方内容之间的空白?
- html - CSS - 在下拉列表周围填充
- wordpress - 仅将下拉菜单应用于主菜单,然后列出不带下拉菜单的子菜单
- php - 我试图了解如何使用一个 PHP“主”文件从多个文本文件生成单个网页
- reactjs - 一个 Animated.Value 与多个用于控制过渡
- python - 如何在 python 中使用 request.get() 和 defaultCredentials?
- laravel - 如何在 Laravel 中使用 Fastexcel 获取工作表名称
- api - Github Rest API:使用多个问题编号进行批量搜索
- javascript - PDF 中的 JavaScript