Impacto en el estilo de GHC-Wall


Se considera una buena práctica habilitar las advertencias GHC con -Wall. Sin embargo, he descubierto que corregir esas advertencias tiene un efecto negativo para algunos tipos de construcciones de código.

Ejemplo 1:

Usar el equivalente de do-notation de f >> generará una advertencia si no uso explícitamente la forma _ <- f:

Warning: A do-notation statement discarded a result of type Char.
         Suppress this warning by saying "_ <- f",
         or by using the flag -fno-warn-unused-do-bind

Entiendo que puedo olvidar hacer algo con el resultado de f. Sin embargo, es legítimo ignorar el resultado (muy común en analizador). No hay advertencia cuando se usa >>, ¿verdad? Usar _ <- es más pesado de lo que debería.

Ejemplo 2:

Nombrar una variable de patrón con el mismo nombre de una función visible dará:

Warning: This binding for `map' shadows the existing binding
           imported from Prelude

Esto está empeorando cuando se usa la sintaxis del registro, ya que el espacio de nombres se contamina rápidamente. La solución es dar un nombre alternativo en la expresión del patrón. Así que termino usando un nombre menos apropiado solo para evitar una advertencia. No siento que sea un razón suficiente.

Sé que puedo usar las opciones -fno-warn-..., pero ¿debo seguir con -Wall después de todo?

Author: gawi, 2010-11-13

6 answers

Ejemplo 1:

He re-aprendido a escribir analizadores en estilo Aplicativo are son mucho más concisos. Por ejemplo, en lugar de:

funCallExpr :: Parser AST
funCallExpr = do
    func <- atom
    token "("
    arg <- expr
    token ")"
    return $ FunCall func arg

En su lugar escribo:

funCallExpr :: Parser AST
funCallExpr = FunCall <$> atom <* token "(" <*> expr <* token ")"

Pero qué puedo decir, si no te gusta la advertencia, deshabilítala como sugiere.

Ejemplo 2:

Sí, encuentro esa advertencia un poco irritante también. Pero me ha salvado un par de veces.

Se vincula con las convenciones de nomenclatura. Me gusta mantener los módulos bastante pequeños, y mantener la mayoría de las importaciones cualificadas (excepto para las importaciones de "notación" como Control.Applicative y Control.Arrow). Eso mantiene bajas las posibilidades de conflicto de nombres, y solo hace que las cosas sean fáciles de trabajar. hothasktags hace que este estilo sea tolerable si está utilizando etiquetas.

Si solo está coincidiendo con un patrón en un campo con el mismo nombre, puede usar -XNamedFieldPuns o -XRecordWildCards para reutilizar el nombre:

data Foo = Foo { baz :: Int, bar :: String }

-- RecordWildCards
doubleBaz :: Foo -> Int
doubleBaz (Foo {..}) = baz*baz

-- NamedFieldPuns
reverseBar :: Foo -> String
reverseBar (Foo {bar}) = reverse bar

Otra convención común es agregar un prefijo húngaro a los sellos discográficos:

data Foo = Foo { fooBaz :: Int, fooBar :: String }

Pero sí, los registros no son divertidos para trabaja con Haskell. De todos modos, mantenga sus módulos pequeños y sus abstracciones apretadas y esto no debería ser un problema. Considéralo como una advertencia que dice simplifyyyy, hombre .

 25
Author: luqui,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2015-02-28 10:05:38

Creo que el uso de -Wall puede conducir a un código menos legible. Especialmente, si está haciendo algo de aritmética.

Algunos otros ejemplos, donde el uso de -Wall sugiere modificaciones con peor legibilidad.

(^) con -Wall requiere firmas de tipo para exponentes

Considere este código:

norm2 x y = sqrt (x^2 + y^2)
main = print $ norm2 1 1

Con -Wall da dos advertencias como esta:

rt.hs:1:18:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral t' arising from a use of `^' at rt.hs:2:18-20
    In the first argument of `(+)', namely `x ^ 2'
    In the first argument of `sqrt', namely `(x ^ 2 + y ^ 2)'
    In the expression: sqrt (x ^ 2 + y ^ 2)

Escribir (^(2::Int) en todas partes en lugar de (^2) no es agradable.

Las firmas de tipo son requerido para todos los niveles superiores

Al escribir código rápido y sucio, es molesto. Para código simple, donde hay como máximo uno o dos tipos de datos en uso (para exapmle, sé que solo trabajo con Doubles), escribir firmas de tipo en todas partes puede complicar la lectura. En el ejemplo anterior hay dos advertencias solo por la falta de firma de tipo:

rt.hs:1:0:
    Warning: Definition but no type signature for `norm2'
             Inferred type: norm2 :: forall a. (Floating a) => a -> a -> a
...

rt.hs:2:15:
    Warning: Defaulting the following constraint(s) to type `Double'
             `Floating a' arising from a use of `norm2' at rt.hs:2:15-23
    In the second argument of `($)', namely `norm2 1 1'
    In the expression: print $ norm2 1 1
    In the definition of `main': main = print $ norm2 1 1

Como distracción, uno de ellos se refiere a la línea diferente de la que es la firma de tipo necesario.

Las firmas de tipo para los cálculos intermedios con Integral son necesarias

Este es un caso general del primer problema. Considere un ejemplo:

stripe x = fromIntegral . round $ x - (fromIntegral (floor x))
main = mapM_ (print . stripe) [0,0.1..2.0]

Da un montón de advertencias. En todas partes con fromIntegral para convertir de nuevo a Double:

rt2.hs:1:11:
    Warning: Defaulting the following constraint(s) to type `Integer'
             `Integral b' arising from a use of `fromIntegral' at rt2.hs:1:11-22
    In the first argument of `(.)', namely `fromIntegral'
    In the first argument of `($)', namely `fromIntegral . round'
    In the expression:
            fromIntegral . round $ x - (fromIntegral (floor x))

Y todo el mundo sabe con qué frecuencia se necesita fromIntegral en Haskell...


Hay más casos como estos el código numérico corre el riesgo de ser ilegible solo para cumplir con los requisitos -Wall. Pero yo sigue usando -Wall en el código del que me gustaría estar seguro.

 10
Author: sastanin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-15 12:12:05

Recomendaría continuar usando '-Wall' como la opción por defecto, y deshabilitar cualquier comprobación que necesite en base local, por módulo usando un pragma OPTIONS_GHC en la parte superior de los archivos relevantes.

El que podría hacer una excepción es de hecho '-fno-warn-unused-do-bind', pero una sugerencia podría ser usar una función 'void' explícita ... escribir 'void f' parece más bonito que '_

En cuanto al sombreado de nombres-creo que generalmente es bueno evitar si puede - ver 'mapa' en el middle of some code llevará a la mayoría de los Haskelers a esperar la biblioteca estándar fn.

 7
Author: BenMos,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-14 07:22:10

El sombreado de nombres puede ser bastante peligroso. En particular, puede ser difícil razonar sobre en qué ámbito se introduce un nombre.

Los enlaces de patrones no utilizados en notación do no son tan malos, pero pueden indicar que se está utilizando una función menos eficiente de la necesaria (por ejemplo, mapM en lugar de mapM_).

Como señaló BenMos, usar void o ignore para descartar explícitamente los valores no utilizados es una buena manera de ser explícito sobre las cosas.

Sería muy bueno poder desactivar advertencias para solo una sección de código, en lugar de para todo a la vez. Además, las banderas cabal y las banderas ghc de la línea de comandos tienen prioridad sobre las banderas en un archivo, por lo que no puedo tener-Wall por defecto en todas partes e incluso simplemente deshabilitarlo para la totalidad de un solo archivo.

 6
Author: sclv,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2011-06-25 16:43:36

También existe la opción mucho menos intrusiva -W, que habilita un conjunto de advertencias razonables relacionadas principalmente con el estilo de codificación general (importaciones no utilizadas, variables no utilizadas, coincidencias de patrones incompletas, etc.).

En particular, no incluye las dos advertencias que usted mencionó.

 4
Author: ertes,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-03-04 05:33:41

Todas estas advertencias ayudan a prevenir errores y deben ser respetadas, no suprimidas. Si desea definir una función con un nombre de Prelude, puede ocultarla utilizando

Import Prelude hiding (map)

La sintaxis'Hiding' solo debe usarse para Prelude y módulos del mismo paquete, de lo contrario se corre el riesgo de que se rompa el código por cambios en la API del módulo importado.

Véase: http://www.haskell.org/haskellwiki/Import_modules_properly

 3
Author: Lemming,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2010-11-21 17:42:26