将IO操作结果存储在LET子句中

Ber*_*ian 0 haskell

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

在我的情况下,我调用了两次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
Run Code Online (Sandbox Code Playgroud)

Dan*_*ner 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)
Run Code Online (Sandbox Code Playgroud)

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

  1. 可以在您的第一个listDirectory和您的目录之间创建该目录createDirectory,从而尝试重新创建已存在的目录并抛出异常.
  2. 即使目录创建失败,也可能在第一个listDirectory和第二个文件之间创建另一个文件listDirectory,True即使您尚未创建新目录,也会导致返回.
  3. 即使目录创建成功,您的第一个listDirectory和第二个文件之间可能会删除另一个文件listDirectory,False即使您已创建新目录,也会返回该文件.

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

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

为了解决这些问题,我建议createDirectory直接调用(即事先没有检查)并使用异常捕获机制来确定它是否失败以及这是因为目录已经存在还是调用现有的createDirectoryIfMissing.