将IO操作存储在LET子句中

时间:2018-08-16 13:58:25

标签: haskell

您好,有人可以向我解释一下,如果您知道从那时起要使用它,那么如何将动作的结果存储在let block中(您需要像标题一样的结果)?

在我的情况下,我两次调用listDirectory,我想将第一次调用的值保存在变量initialList中,以便稍后将其长度与以后调用的listDirectory进行比较。

如何将listDirectory的第一次调用存储在变量initialList中?

module Main where 

import System.IO
import System.Directory
import DB(db)
import Company

main::IO()
main = do
    putStrLn "Insert folder for output:"
    folder<-getLine
    makeDir folder>>= \b -> 
        putStrLn (if b then "Created" else "Existed Already")

makeDir::String->IO  Bool
makeDir dirname=let root="D:\\"
                    enumerateDirs=listDirectory root
                    initialList=<<enumerateDirs in  //how can i store it here?

     if  dirname `elem` initialList then
        putStrLn "Directory found , folder count:"++length initialList
     else  
        createDirectory root++dirname>>
        length enumerateDirs >initialList

1 个答案:

答案 0 :(得分:8)

对IO操作使用绑定而不是let / =。像这样:

makeDir dirname = do
    let root = "D:\\"
    initialList <- listDirectory root
    if dirname `elem` initialList then
        putStrLn ("Directory found, folder count: " ++ length initialList)
    else createDirectory (root ++ dirname)
    finalList <- listDirectory root
    return (length finalList > length initialList)

但是,这种用于创建目录的技术存在一些问题。因为您可能不是唯一正在运行的程序:

  1. 可能在您的第一个listDirectorycreateDirectory之间创建了目录,导致您尝试重新创建一个已经存在的目录并引发异常。
  2. 即使目录创建失败,也可能在第一个listDirectory和第二个listDirectory之间创建另一个文件,即使您尚未创建目录,也会导致返回True新目录。
  3. 即使目录创建成功,您的第一个listDirectory和第二个listDirectory之间的另一个文件也可能被删除,即使您创建了新目录,也会导致您返回False

另外,因为dirname来自未经过滤的用户输入:

  1. 如果用户输入包含反斜杠,dirname `elem` initialList检查将在错误的目录列表中查找错误的目录名称。例如,如果用户输入a\b,则当该代码应在目录列表中寻找a\b时,此代码将在目录列表中搜索D:\b。对于这种输入,D:\a比较的逻辑同样是不正确的。

要解决这些问题,我建议直接调用length(即事先没有检查),并使用异常捕获机制来确定它是否失败以及是否由于目录已经存在或调用现有的{ {1}}。