2009-07-21 11 views
9

Tengo una pregunta muy simple. Me gustaría usar una cláusula where después de un bloque de código que usa operadores de enlace, pero obtengo un error de compilación.Haskell: ¿Puedo usar una cláusula where después de un bloque con operadores de vinculación (>> =)?

Aquí está 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 me gusta mucho 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' 

Mismo problema. ¿Puedo usar una cláusula Where en estas circunstancias?

Respuesta

10

Como lo explica ephetherient, no puede usar las cláusulas where de la forma en que lo hace.

El error se debe a que en este código:

main = 
    return [1..10] >>= \list -> 
    print list' 
    where 
     list' = reverse list 

El -clause 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 tiene el "out of scope" Error: 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 suelo hacer en esta situación (y me han mordido la misma cosa un montón de veces). Simplemente introduzco una función y paso 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 línea let vinculante. Si el código dentro de la función f es muy pequeño, simplemente lo escribiría dentro del enlace let, y no pasaría por alto la introducción de una nueva función.

+0

Gracias, tu ejemplo con más paréntesis lo aclara. –

1

Por lo que puedo decir, la cláusula where solo se usa en enlaces locales. La parte interna de una declaración de enlace >> (=) no es un enlace local (dos tipos diferentes de enlaces en esa oración).

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 syntax report - no está seguro de la cantidad de ayuda que sería.

Si me equivoco, alguien ciertamente me va a corregir, pero estoy bastante seguro de que no puede usar una cláusula where en el estilo que ha mostrado anteriormente. list nunca estará en el alcance de una cláusula where a menos que sea un parámetro de la función.

+0

Una abstracción lambda es una expresión, no una declaración o unión, aunque puede vincular nuevos nombres ... – ephemient

+0

Whoa, ¿quién ha hecho esto? Creo que es correcto, si no tan completo como podría ser. – ephemient

+0

no es relevante. el OP quiere usar "lista", un resultado del medio de un grupo de cálculos monádicos; no es un valor que está fuera de la mónada – newacct

11

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) vinculante.

Desde el informe de Haskell 98 en declarations and bindings,

p | g1=e1
    | g2=e2
    …
    | gm=em
  where {decls}

es azúcar para

p= letdeclsin
      ifg1thene1else
      ifg2thene2else
      …
      ifgmthenemelse error "Unmatched pattern"

o, lo que simplifica las cosas mediante la eliminación de los guardias,

p=ewhere {decls}

es azúcar para

tanto en enlaces de funciones como de patrones. Esto es cierto incluso cuando su e es un do { & hellip; } constructo.

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).

Ni siquiera se puede escribir

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    (print list' where list' = reverse list) 

porque "ewhere {decls}" no es una expresión legal – where sólo se puede utilizar en las declaraciones y enlaces.

main = do 
    putStrLn "where clause test: " 
    list <- return [1..10] 
    let list' = list'' where list'' = reverse list 
    print list' 

Esto es legal (si algo inventado).

+0

¿por qué no simplemente "let list" = reverse list "? en el ultimo ejemplo? – newacct

+0

Gracias, debería consultar el Informe Haskell con más frecuencia cuando tenga preguntas fundamentales sobre este idioma. –

+0

@newacct: la pregunta de OP ya incluye esa variante, que obviamente funciona. – ephemient

Cuestiones relacionadas