Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/delphi/8.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Haskell ghci能否在非安全性能IO块内重新排序IO操作_Haskell_Ghci - Fatal编程技术网

Haskell ghci能否在非安全性能IO块内重新排序IO操作

Haskell ghci能否在非安全性能IO块内重新排序IO操作,haskell,ghci,Haskell,Ghci,是否可以对unsafePerformIO内的IO块调用中的IO操作重新排序? 我有有效的IO功能 assembleInsts :: ... -> IO S.ByteString assembleInsts ... = do tmpInputFile <- generateUniqueTmpFile writeFile tmpInputFile str (ec,out,err) <- readProcessWithExitCode asm_exe [tmp

是否可以对
unsafePerformIO
内的IO块调用中的IO操作重新排序?

我有有效的IO功能

assembleInsts :: ... -> IO S.ByteString
assembleInsts ... = do
    tmpInputFile <- generateUniqueTmpFile
    writeFile tmpInputFile str
    (ec,out,err) <- readProcessWithExitCode asm_exe [tmpInputFile] ""
    -- asm generates binary output in tmpOutputFile
    removeFile tmpInputFile
    let tmpOutputFile = replaceExtension tmpIsaFile "bits" -- assembler creates this
    bs <- S.readFile tmpOutputFile -- fails due to tmpOutputFile not existing
    removeFile tmpOutputFile
    return bs
此外,我在模块顶部添加了以下注释 按照文档的(
System.IO.Unsafe
)说明

{-# OPTIONS -fno-cse #-}
module Gen.IsaAsm where
(我也尝试添加了
-fnofull lazness
,正如一篇参考文章所说的那样 我咨询过,但编译器拒绝了。我不这么认为 不过,这种情况在这里也适用。)

ghci
中运行时,会报告以下错误

*** Exception: C:\Users\trbauer\AppData\Local\Temp\tempfile_13516_0.dat: openBinaryFile: does not exist (No such file or directory)
但是如果我删除
removefiletmpoutputfile
,它就会神奇地工作。 因此,
removeFile
似乎在进程终止之前执行。 这可能吗?bytestring非常严格,我甚至尝试在某一点上使用以下命令强制输出:

S.length bs `seq` return ()
删除文件之前

import qualified Data.ByteString.Lazy as S
...
    let tmpDatFile = tmpOutputFile
是否有方法转储中间代码以了解发生了什么? (也许我可以用Process Monitor或其他什么东西来追踪这一点。) 不幸的是,我想在此操作中进行清理(删除文件)

我认为exe版本可能会工作,但在ghci下它会失败(解释)。 我正在使用上一个Haskell平台中的GHC 7.6.3


我知道
unsafePerformIO
是一个非常大的问题,并且有其他相关风险,但它确实会限制我的软件更改的复杂性。

这可能不适用,因为它是基于您问题中未指定的假设。特别是,这个答案基于以下两个假设<未指定的code>S是
数据.ByteString.Lazy
tmpDatFile
,未定义的是
tmpoutfile

import qualified Data.ByteString.Lazy as S
...
    let tmpDatFile = tmpOutputFile
可能原因 如果这些假设成立,
removeFile
将过早运行,即使不使用
unsafePerformIO
。下面的代码

import System.Directory
import qualified Data.ByteString.Lazy as S

assembleInsts = do
    -- prepare a file, like asm might have generated
    let tmpOutputFile = "dataFile.txt"
    writeFile tmpOutputFile "a bit of text"
    -- read the prepared file 
    let tmpDatFile = tmpOutputFile
    bs <- S.readFile tmpOutputFile
    removeFile tmpDatFile
    return bs

main = do
    bs <- assembleInsts
    print bs
而是产生正确的输出

“一点文字”

解释
Data.ByteSting.Lazy
readFile
文档声明它将

通过testring将整个文件惰性地读入
中。手柄将保持打开状态,直到遇到EOF

在内部,
readfile
通过调用
unsafeInterleaveIO
来实现这一点
unsafeInterleaveIO
延迟IO代码的执行,直到对其返回的术语进行计算

hGetContentsN :: Int -> Handle -> IO ByteString
hGetContentsN k h = lazyRead -- TODO close on exceptions
  where
    lazyRead = unsafeInterleaveIO loop

    loop = do
        c <- S.hGetSome h k -- only blocks if there is no data available
        if S.null c
          then do hClose h >> return Empty
          else do cs <- lazyRead
                  return (Chunk c cs)
hGetContentsN::Int->Handle->IO ByteString
hGetContentsN k h=lazyRead——异常时关闭TODO
哪里
lazyRead=未缓冲的交错循环
循环=do
c>返回空

否则,即使您使用的是
unsafePerformIO
,也不应重新排序IO操作。如果您想确定这一点,可以使用
-ddump siml
标志查看GHC生成的中间核心语言,甚至其中一种语言显示汇编之前的所有编译中间步骤


我知道这回答了您的问题,而不是您实际需要的,但您至少可以排除GHC bug。不过,GHC中似乎不太可能存在影响此功能的bug。

完全是我的错。。。。对不起大家。GHC不会在上述条件下对IO块中的IO操作重新排序。汇编程序未能汇编输出并创建假定的文件。我只是忘记检查汇编器的退出代码或输出流。我假设输入在语法上是正确的,因为它是生成的,汇编程序拒绝了它,只是无法创建文件。它给出了一个有效的错误代码和错误诊断,所以这对我来说真的很糟糕。我可能第一次使用了
readProcess
,这会在非零退出时引发异常,但最终一定会改变这一点。我认为汇编程序有一个错误,在某些情况下,它没有正确地指示失败的退出代码,我不得不从
readProcessWithExitCode
更改

我仍然不确定当我省略
removeFile
时,错误为什么消失了

import qualified Data.ByteString.Lazy as S
...
    let tmpDatFile = tmpOutputFile

我想删除这个问题,但我希望上面的建议也能帮助其他人调试类似的(更有效的)问题。我已经被Cirdec提到的懒惰IO事情烧坏了,chi提到的
-ddump siml
标志也很好地知道。

我的第一个猜测是
readProcessWithExitCode
S.readFile
正在做懒惰I/O。。。尽管我猜测,
S
代表
Data.ByteString.Strict
。。。所以我不确定。值得一看吗?“
readProcessWithExitCode
创建一个外部进程,严格读取其标准输出和标准错误,等待进程终止,然后返回进程的
ExitCode
、标准输出和标准错误。”是
S
数据.ByteString.Lazy
还是
数据.ByteString.Strict
?如果
S
Data.ByteString.Lazy
,那么
tmpDatFile
是什么,它与
tmpOutputFile
有何不同?抱歉,我更正了歧义
S
是一个严格的字节字符串
tmpDatFile
确实应该是
tmpOutputFile
。它是由通过
readProcessWithExitCode
启动的外部进程创建的。标准输出流被忽略且不需要。对于建议的解决方案,
S
实际上是一个严格的字节字符串。即使如此,在删除文件之前,我还是尝试通过在
S.length
中输入
seq
来强制输出。这并没有改变结果。