Haskell: ¿Puedo usar una cláusula where después de un bloque con los operadores bind (>> =)?
Pregunta
Tengo una pregunta muy simple. Me gustaría utilizar una cláusula where después de un bloque de código que utiliza operadores se unen pero me da un error de compilación.
Este es un ejemplo sencillo:
main =
putStrLn "where clause test:" >>
return [1..10] >>= \list ->
print list'
where list' = reverse list -- test1.hs:5:28: Not in scope: `list'
Puedo utilizar una cláusula let para la lista' como en
main =
putStrLn "where clause test:" >>
return [1..10] >>= \list ->
let list' = reverse list -- works of course
in print list'
pero realmente me gustaría que si podía usar una cláusula where ...
También probé con la notación do
main = do
putStrLn "where clause test:"
list <- return [1..10]
print list'
where list' = reverse list --test3.hs:5:30: Not in scope: `list'
El mismo problema. ¿Puedo utilizar una cláusula where en estas circunstancias?
Solución
Como ephemient explica, no se puede utilizar where
cláusulas de la forma de hacer.
El error se debe a que en este código:
main =
return [1..10] >>= \list ->
print list'
where
list' = reverse list
La cláusula where
está unido a la función principal.
Aquí está la misma función con más paréntesis:
main = return [1..10] >>= (\list -> print list')
where
list' = reverse list
Creo que es bastante obvio por qué se obtiene el error "out of scope
": La unión de list
es más profundo de la expresión main
, no es algo que la cláusula where
puede alcanzar
Lo que suele hacer en esta situación (y me ha picado la misma cosa que un montón de veces). Simplemente presento una función y pasar el list
como argumento.
main = do
list <- return [1..10]
let list' = f list
print list'
where
f list = reverse list -- Consider renaming list,
-- or writing in point-free style
Por supuesto, imaginar su código real en la función f
es mucho más que simplemente reverse
y es por eso que desea que el interior de una cláusula where
, en lugar de una unión let
en línea. Si el código dentro de la función f
es muy pequeño, que acababa de escribir dentro de la unión del let
, y no iría a través de la sobrecarga de la introducción de una nueva función.
Otros consejos
El problema es que let
-in
es una expresión, que se puede utilizar dentro de otras expresiones, mientras que where
sólo se puede utilizar en un (módulo | clase | ejemplo | GADT | ...) declaración o una (función | patrón ) de unión.
Desde el informe de Haskell 98 en las declaraciones rel="noreferrer"> ,
p | g 1
=
e 1
| g 2=
e 2
...
| g m=
e m
where {
decls}
es el azúcar para
p
= let
declsin
if
g 1then
e 1else
if
g 2then
e 2else
...
if
g mthen
e melse error "Unmatched pattern"
o, lo que simplifica las cosas mediante la eliminación de los guardias,
p
=
ewhere {
decls}
es el azúcar para
p
= let
declsin
e
en ambas fijaciones de función y el patrón. Esto es cierto incluso cuando el e es un constructo do {
... }
.
Si usted quiere tener un local de la unión a una subexpresión particular dentro de una expresión mayor, es necesario utilizar let
-in
(o simplemente let
dentro de un do
, pero eso es sólo azúcar para let
-in
).
No se puede incluso escribir
main = do
putStrLn "where clause test: "
list <- return [1..10]
(print list' where list' = reverse list)
porque " e where {
decls }
" no es una expresión legal -. where
sólo se puede utilizar en las declaraciones y los enlaces
main = do
putStrLn "where clause test: "
list <- return [1..10]
let list' = list'' where list'' = reverse list
print list'
Esto es legal (si es un tanto artificial).
Por lo que yo puedo decir, la cláusula where sólo se utiliza en fijaciones locales . La parte interior de un >> (=) Estado de unión no es una unión (dos diferentes tipos de fijaciones en esa frase) locales.
Comparar con esto:
main = f [1..10]
f list =
putStrLn "where clause test:" >> print list'
where list' = reverse list
Es posible que desee hacer referencia a la Haskell 98 sintaxis informe - no seguro de la cantidad de ayuda que sería.
Si estoy equivocado, alguien sin duda me corrija, pero estoy bastante seguro de que no se puede utilizar una cláusula where en absoluto en el estilo que has mostrado anteriormente. list
nunca será en su alcance a una cláusula donde a menos que sea un parámetro a la función.