我是 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
表达式的
layout,因此必须用分号明确分隔各个选项。
如果您在
where
子句中声明的表达式之一后添加分号,则该分号将被解释为分隔该 where
子句中声明的表达式。因此分号必须位于 where
的布局块之外。一种解决方案是将 where
子句本身括在大括号中:
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
但是惯用的 Haskell 会利用布局并避免任何分号:
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