我基本上是在工作目录的“res”文件中定义给定文件的路径,我所做的如下:
iZone :: [Char]
iZone = "21.evt"
iZonePath :: String IO
iZonePath = result
where
path <- getCurrentDirectory
result = (path ++ /res/ ++ iZone)
然而,ghc与
交流src / Main.hs:15:8:错误:
parse error on input ‘<-’ Perhaps this statement should be within a 'do' block? | 15 |
路径&lt; - getCurrentDirectory
这是什么原因?我不能在“where”块中使用“&lt; - ”操作吗?
答案 0 :(得分:3)
IO monad旨在强制程序员在副作用中选择特定的顺序。
假设允许这样做:
foo :: IO ()
foo = do
putStrLn "1"
putStrLn x
putStrLn "2"
putStrLn x
putStrLn "3"
where
x <- putStrLn "x generated here" >> return "x used here"
输出是什么?
在打印x generated here
之前,do
块的最开头是否打印了1
?就在那之后?
x generated here
打印一次还是两次?
如果它在开始时发生过一次,那么简单地编写
会更清楚foo :: IO ()
foo = do
x <- putStrLn "x generated here" >> return "x used here"
putStrLn "1"
putStrLn x
putStrLn "2"
putStrLn x
putStrLn "3"
如果以后要执行,我们可以将其移至想要的位置。
如果它意味着要运行两次,我们可以写
foo :: IO ()
foo = do
x1 <- generateX
putStrLn "1"
putStrLn x1
putStrLn "2"
x2 <- generateX
putStrLn x2
putStrLn "3"
where
generateX = putStrLn "x generated here" >> return "x used here"
(或者,为了更具可读性,请使用let
代替where
)
在上面的代码中,很明显generateX
在精确点上运行了两次。
允许where x <- ...
会导致执行不清楚。相反,do
会使其变得精确。
实际上,do
块的整个语法可以根据monadic操作>>=
和return
进行重写,这保证了IO操作的明确排序。
原则上,人们可以扩展Haskell并定义where x <- ...
,至少在某些情况下允许它,但似乎没有什么可以做到这一点,以及丢失代码清晰度的东西。