不能在 where 块中使用“<-”吗?
Can't "<-" be used in a where block?
我基本上是在尝试在工作目录的 "res" 文件中定义给定文件的路径,我所做的如下:
iZone :: [Char]
iZone = "21.evt"
iZonePath :: String IO
iZonePath = result
where
path <- getCurrentDirectory
result = (path ++ /res/ ++ iZone)
但是,ghc 符合
src/Main.hs:15:8: error:
parse error on input ‘<-’
Perhaps this statement should be within a 'do' block? | 15 |
path <- getCurrentDirectory
这是什么原因?我不能在 "where" 块中使用“<-”operation 吗?
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
块的整个语法可以根据单子操作 >>=
和 return
重写,这保证了 IO 操作的明确顺序。
原则上,可以扩展 Haskell 并定义 where x <- ...
,至少在某些情况下允许这样做,但这样做似乎没有任何好处,而且代码清晰度也会有所损失.
我基本上是在尝试在工作目录的 "res" 文件中定义给定文件的路径,我所做的如下:
iZone :: [Char]
iZone = "21.evt"
iZonePath :: String IO
iZonePath = result
where
path <- getCurrentDirectory
result = (path ++ /res/ ++ iZone)
但是,ghc 符合
src/Main.hs:15:8: error:
parse error on input ‘<-’ Perhaps this statement should be within a 'do' block? | 15 |
path <- getCurrentDirectory
这是什么原因?我不能在 "where" 块中使用“<-”operation 吗?
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
块的整个语法可以根据单子操作 >>=
和 return
重写,这保证了 IO 操作的明确顺序。
原则上,可以扩展 Haskell 并定义 where x <- ...
,至少在某些情况下允许这样做,但这样做似乎没有任何好处,而且代码清晰度也会有所损失.