Haskell-在List Monad中期望[Char]时获取Char类型

时间:2019-05-02 17:45:53

标签: haskell io monads

我正在通过尝试创建一个找到.mp3和.flac元数据并将其整齐地写入文件的程序来练习Haskell。我已经走了这么远,但是我对应该做的事情感到很沮丧。这是这里的主要代码块:

builddir xs = do
    writeto  <- lastest getArgs
    let folderl b = searchable <$> (getPermissions b)
    let filel   c = ((lastlookup mlookup c) &&) <$> ((not <$> folderl c))
    a <- listDirectory xs
    listdirs <- filterM (folderl) (map ((xs ++ "/") ++) a)
    filedirs <- filterM (filel)   (map ((xs ++ "/") ++) a)
    let tagfiles = mapM (tagsort) filedirs
    putStrLn $ concat listdirs
    putStrLn $ concat tagfiles


tagsort xs = do
    nsartist <- getTags xs artistGetter
    nsalbum  <- getTags xs albumGetter
    artist   <- init $ drop 8 $ show nsalbum
    album    <- init $ drop 7 $ show nsalbum
    (artist ++ " - " ++ album)

我知道,这很混乱。在ghci中运行时,我得到了:

• Couldn't match expected type ‘[Char]’ with actual type ‘Char’
• In the first argument of ‘(++)’, namely ‘artist’
  In a stmt of a 'do' block: artist ++ " - " ++ album
  In the expression:
    do nsartist <- getTags xs artistGetter
       nsalbum <- getTags xs albumGetter
       artist <- init $ drop 8 $ show nsalbum
       album <- init $ drop 7 $ show nsalbum
       ....
       60    artist ++ " - " ++ album

我无法理解为什么会这样。在我的测试程序中运行类似的命令:

main = do
artg <- getTags "/home/spilskinanke/backlogtest/02 - await rescue.mp3" artistGetter
let test = init $ drop 8 $ show artg
print test

这完全正常。将字符串“ 65daysofstatic”输出到我在ghci中的终端。显然不是Char类型。那么为什么在我的代码中被称为Char? 还要注意,在添加任何引用我正在使用的元数据模块的代码段(htaglib)之前,该程序在测试中运行良好。使用tagfiles函数和tagort monad不存在,我可以为某个目录设置arg,并且我的测试将成功打印一个包含所有可读文件夹的FilePath列表,以及另一个包含所有以我所需的结尾的文件的FilePaths列表。 mlookup,在这种情况下为.mp3,.mp4,.flac和.wav。任何帮助将不胜感激。

1 个答案:

答案 0 :(得分:6)

您在IO中混合了[]tagsort

tagsort xs = do

    -- Okay, run IO action and bind result to ‘nsartist’
    nsartist <- getTags xs artistGetter

    -- Similarly for ‘nsalbum’
    nsalbum  <- getTags xs albumGetter

    -- Mistaken: ‘init …’ returns a list, not an ‘IO’ action
    artist   <- init $ drop 8 $ show nsalbum
    album    <- init $ drop 7 $ show nsalbum

    -- You are also missing a ‘pure’ or ‘return’ here
    (artist ++ " - " ++ album)

修复很简单:使用let语句而不是bind语句<-,并添加pure以使IO String中的String },您有

tagsort xs = do
    nsartist <- getTags xs artistGetter
    nsalbum  <- getTags xs albumGetter
    let artist = init $ drop 8 $ show nsalbum
    let album = init $ drop 7 $ show nsalbum
    pure (artist ++ " - " ++ album)

通常来说,每个do块都必须位于一个monad中,直到您开始学习使用monad变换器组合不同效果的知识为止。因此,在IO块中,绑定语句右边的任何内容都必须是IO动作;如果您只想进行纯计算,则可以使用let(如果不需要将某些内容绑定到名称,则可以使用内联表达式)。最后,do块中的最后一条语句也必须是特定monad中的一个动作-这通常是一个纯值,只是用pure :: Applicative f => a -> f a(或return :: Monad m => a -> m a包裹在monad中,这样做是一样的,但是由于约束Monad的约束更严格,因此在较少的上下文中工作。

相关问题