对于使用目录漫游器的应用程序,如果文件可访问,我需要信息,真实文件,需要区分文件和目录条目。
我想:
因此,所有文件都可以被读取并且可以被操作并驻留在允许该文件的目录中。
这就是我提出的:
fileType :: FilePath -> IO Int
fileType f = do
-- skip any symbolic link
l <- getSymbolicLinkStatus f
if isSymbolicLink l
then return 0 -- link
else do
s <- getFileStatus f
if isRegularFile s
then do
-- files need read and write
facc <- fileAccess f True True False
if facc
then return 1
else return 0 -- file but not RW
else if isDirectory s
then do
-- dirs need read and execute
dacc <- fileAccess f True False True
if dacc
then return 2
else return 0 -- dir but not RX
else return 0 -- not a file or dir
但是我对这个实现非常不确定,并且想问一下我能做些什么来使这个更简洁。
例如,我有一种感觉,我至少可以移动&#34;返回&#34;在顶部的某个地方。但是尝试这个我无法确定类型。
P.S。:对我来说,返回Int 0 1 2(而不是特殊的数据类型)是好的,但我不介意,如果改变了。
答案 0 :(得分:4)
您可以使用sum类型来表示不同的文件类型,而不是使用Int
来跟踪不同的文件类型:
data FileType = SymbolicLink -- Symbolic link
| FileRead -- File with Read Permission
| DirRead -- Directory with Read Permission
| DirNoRead -- Directory with No Read Permission
| FileNoRead -- File with No Read Permssion
| NotFileAndDir -- Neither File nor directory
deriving (Show)
我可以在您的代码中看到的一种模式是,有各种嵌套的monadic if if检查条件,然后根据它返回适当的结果。您可以看到标准库是否提供了这样的抽象,或者它是否可以为您自己编写:
bdef :: (Monad m) => m Bool -> m a -> m a -> m a
bdef mb t f = mb >>= \x -> if x then t else f
在bdef
函数中,如果mb
为IO True
,则我会回溯第一个参数或第二个参数。请注意,它不需要IO
,但它可以是任何monad。一旦定义了这个,剩下的就是定义剩下的函数:
filetype :: FilePath -> IO FileType
filetype f = sym
where sym = bdef (isSymbolicLink <$> getSymbolicLinkStatus f)
(return SymbolicLink) reg
reg = bdef (isRegularFile <$> fStatus)
(bdef checkfRead (return FileRead) (return FileNoRead)) dir
dir = bdef (isDirectory <$> fStatus)
(bdef checkDRead (return DirRead) (return DirNoRead))
(return NotFileAndDir)
checkfRead = fileAccess f True True False
checkDRead = fileAccess f True False True
fStatus = getFileStatus f
示例ghci
演示:
λ> filetype "/home/sibi/test.hs"
FileRead
λ> filetype "/home/sibi"
DirRead
答案 1 :(得分:2)
阅读完其他答案和评论后(非常感谢!)我想回答我自己的问题并告诉你我的想法:
data FileType = Skip | File | Dir
getFileType :: FilePath -> IO FileType
getFileType f = getSymbolicLinkStatus f >>= testIt
where testIt s
| isSymbolicLink s = return Skip
| isRegularFile s = useWhen (fileAccess f True True False) File
| isDirectory s = useWhen (fileAccess f True False True) Dir
| otherwise = return Skip
useWhen p t = p >>= \b -> if b then return t else return Skip
我做的是: