从某本书中我有以下代码片段
mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do
mvec <- GM.new (n + 1)
go n mvec
where
go 0 v = return v
go n v = (MV.write v n 0) >> go (n - 1) v
mutableUpdateST :: Int -> V.Vector Int
mutableUpdateST n =
runST $ do
mvec <- GM.new (n + 1)
go n mvec
where
go 0 v = V.freeze v
go n v = (MV.write v n 0) >> go (n - 1) v
像hindent
一样缩进它们。现在我想介绍所有大括号和分号,因此空格不再相关。只是因为我很好奇。
第二个示例表明,where
属于整个runST $ do ...
表达式,但第一个示例表明,where在某种程度上是go n mvec
语句的一部分。阅读Haskell Report Chapter 2.7我尝试在第一个例子中引入大括号和分号,如
mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do {
mvec <- GM.new (n + 1);
go n mvec;
where {
go 0 v = return v;
go n v = (MV.write v n 0) >> go (n - 1) v;
} ; }
但是我得到了一个解析错误。那是为什么?
为什么布局hindent
会为第一个示例mutableUpdateIO
生成有效的Haskell?不应该像我上面的尝试那样引入括号和分号吗?
答案 0 :(得分:9)
where
块既不属于runST $ do ...
表达式,也不属于go n mvec
语句;它们属于mutableUpdateIO n = ...
声明和mutableUpdateST n = ...
声明。大括号和分号应该是这样的:
mutableUpdateIO :: Int -> IO (MV.MVector RealWorld Int)
mutableUpdateIO n = do {
mvec <- GM.new (n + 1);
go n mvec;
} where {
go 0 v = return v;
go n v = (MV.write v n 0) >> go (n - 1) v;
}
第2.7章报告中非正式描述的相关句子是:
每当包含布局列表的句法类别结束时,也会插入一个闭括号;也就是说,如果在近距离支撑合法的位置遇到非法词汇,则会插入一个紧支撑。
由于where
是表达式中的非法词汇,因此结束do
块并在那里插入一个紧括号。这也解释了为什么所产生的布局是合法的。