我正在通过尝试创建一个找到.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。任何帮助将不胜感激。
答案 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
的约束更严格,因此在较少的上下文中工作。