haskell - ¿Qué sangrado se requiere para una declaración de caso dentro de una declaración let?
indentation do-notation (2)
Trabajando en Haskell, encontré un comportamiento extraño, lo despojé hasta los huesos
Esto funciona
a :: Bool
a = case True of
True -> True
False -> False
Pero cuando lo intento
b :: IO Bool
b = do
let b'' = case True of
True -> True
False -> False
return b''
yo obtengo
ghci>:l test.hs
[1 of 1] Compiling Main ( test.hs, interpreted )
test.hs:16:14: parse error on input ‘->’
Failed, modules loaded: none.
Así que lo intento
c :: IO Bool
c = do
let c'' = case True of
True -> True
False -> False
return c''
Y esto funciona.
¿Qué? ¿Por qué? ¿Por qué necesito una sangría adicional en este caso? No puedo encontrar nada sobre esto, probablemente porque estas palabras clave son muy cortas y comunes en el lenguaje cotidiano. ¿Hay alguna especificación que explique este comportamiento?
Las reglas básicas de sangría son en realidad bastante simples:
-
después de las palabras clave que comienzan un bloque (
where
,let
,do
,case .. of
) anote la columna donde comienza la siguiente palabra (que podría estar en la línea siguiente) - líneas sangradas exactamente como que son nuevas entradas en el bloque
- líneas sangradas más que eso continúan la entrada anterior
- una línea sangrada menos que eso termina el bloque justo antes de esa línea
- en bloques anidados, aplique las reglas al bloque más externo, primero
Ejemplo complicado:
1 + case x of
A -> 45 -- note where "A" starts
B -> 10 -- same indentation: another case branch
+ 2 -- more indented, so it''s "10+2"
+ 10 -- less indented, so it''s "1+(case ...)+10"
En tu caso,
let b'' = case True of
True -> True
False -> False
tenemos dos bloques anidados, uno para
let
y otro para
case..of
.
Los bloques
let
usan la columna de
b''
.
El
case..of
bloque intenta reutilizar la misma columna, pero primero debemos aplicar las reglas al bloque más externo.
Entonces, la línea
True -> ...
es en realidad una nueva entrada del bloque
let
.
Esto desencadena un error de análisis.
No tengo la redacción exacta de la especificación, pero esta página de Wikibook explica el problema con bastante claridad.
La razón por la que funciona así es simple: para admitir la vinculación de múltiples variables a través de un solo let-group, como:
c = do
let c'' = …
d = …
e = …
return c''
Su
True -> …
y
False -> …
se interpretan erróneamente como variables adicionales a vincular.