我是 Haskell 的新手,有一项大学家庭作业,编译后发现一行只有一个分号。我很好奇,这是否是预期的行为,如果是,为什么?
(过去几天我编写了一些有趣的代码行,但它们并没有按预期工作,每一个都是一个小讲座,例如,--|
不是注释掉的保护,而是未定义的运算符等。)
我唯一能用的版本是(完整代码如下):
case input of {
... -- some other code
('0':xs) -> [(next Zero, rest)] where (next, rest) = readAll xs
;
... -- some other code
}
我想知道是否有可能在没有由单个分号组成的行的情况下做到这一点,以及为什么下面的例子不起作用。
我试过例如
('0':xs) -> [(next Zero, rest)] where (next, rest) = readAll xs;
('0':xs) -> [(next Zero, rest)] where (next, rest) = (readAll xs);
('0':xs) -> [(next Zero, rest)]
where
(next, rest) = (readAll xs);
但它们都导致了同一种错误:
file.hs:19:8: error: parse error on input ‘(’
|
19 | ('1':xs) -> [(next One , rest)] where (next, rest) = readAll xs
| ^
可运行的代码片段:
data BinaryDigit = Zero | One
data BinaryNumber = L BinaryDigit -- L: last digit
| E BinaryDigit BinaryNumber -- E: intermediate digit
instance Show BinaryNumber where
show (L Zero) = "0"
show (L One ) = "1"
show (E digit next) = show (L digit) ++ show next
instance Read BinaryNumber where
-- idea:
-- next item must be known to decide whether E or L constructor to use
-- create function that will be called on the next element and returns the right constructor,
-- with only one parameter, the current digit value, unset
readsPrec _ input = case input of {
('0':'0':xs) -> readsPrec 0 ('0':xs);
('0':'1':xs) -> readsPrec 0 ('1':xs);
('0':xs) -> [(next Zero, rest)] where (next, rest) = readAll xs
;
('1':xs) -> [(next One , rest)] where (next, rest) = readAll xs
;
otherwise -> [];
} where
readAll :: String -> (BinaryDigit -> BinaryNumber, String)
readAll ('0':xs) = ((`E` (next Zero)), rest) where (next, rest) = readAll xs
readAll ('1':xs) = ((`E` (next One )), rest) where (next, rest) = readAll xs
readAll str = (L, str)
main = putStrLn $ show (read "110" :: BinaryNumber)
您之所以需要分号,是因为您在第 15 行和第 23 行使用花括号禁用了表达式的布局
case
,因此必须用分号明确分隔替代方案。如果在子句中声明的表达式之一后添加分号
where
,则该分号将被解释为分隔该子句内声明的表达式where
。因此,分号必须位于 thatwhere
的布局块之外。一种解决方案是将where
子句本身括在花括号中:但惯用的 Haskell 会利用布局并避免使用分号: