haskell coding-style conventions

Buenas normas de codificación Haskell



coding-style conventions (5)

Algunas buenas reglas de pulso imho:

  • Consulte con HLint para asegurarse de que no tenga llaves redundantes y de que su código no tenga puntaje completo.
  • Evite volver a crear funciones de biblioteca existentes. Hoogle puede ayudarte a encontrarlos.
    • Muchas veces las funciones de biblioteca existentes son más generales de lo que uno iba a hacer. Por ejemplo, si quieres Maybe (Maybe a) -> Maybe a , entonces join hace eso, entre otras cosas.
  • La denominación de argumento y la documentación son importantes a veces.
    • Para una función como replicate :: Int -> a -> [a] , es bastante obvio lo que hace cada uno de los argumentos, solo de sus tipos.
    • Para una función que toma varios argumentos del mismo tipo, como isPrefixOf :: (Eq a) => [a] -> [a] -> Bool , la nomenclatura / documentación de argumentos es más importante.
  • Si una función existe solo para servir a otra función, y no es útil de otro modo, y / o es difícil pensar en un buen nombre para ella, entonces probablemente debería existir en la cláusula where de quien llama where lugar de en el alcance del módulo.
  • SECO
    • Use Template-Haskell cuando sea apropiado.
    • Los paquetes de funciones como zip3 , zipWith3 , zip4 , zipWith4 , etc. son muy malos. Use el estilo Applicative con ZipList s en su lugar. Probablemente nunca necesites funciones como esas.
    • Derivar instancias automáticamente El paquete derive puede ayudarlo a derivar instancias para clases de tipos como Functor (solo hay una forma correcta de hacer que un tipo sea una instancia de Functor ).
  • El código que es más general tiene varios beneficios:
    • Es más útil y reutilizable.
    • Es menos propenso a errores porque hay más restricciones.
      • Por ejemplo, si desea programar concat :: [[a]] -> [a] , y observe cómo puede ser más general como join :: Monad m => m (ma) -> ma . Hay menos margen de error al programar la join porque cuando se programa concat puede revertir las listas por error y al join hay muy pocas cosas que puede hacer.
  • Cuando utilice la misma pila de transformadores de mónada en muchos lugares de su código, cree un sinónimo de tipo para él. Esto hará que los tipos sean más cortos, más concisos y más fáciles de modificar a granel.
  • Tenga cuidado con "IO perezoso". Por ejemplo, readFile realmente no lee el contenido del archivo en el momento en que se lee el archivo.
  • Evite sangrar tanto que no pueda encontrar el código.
  • Si su tipo es lógicamente una instancia de una clase de tipo, conviértalo en una instancia.
    • La instancia puede reemplazar otras funciones de interfaz que haya considerado con otras familiares.
    • Nota: si hay más de una instancia lógica, cree newtype-wrappers para las instancias.
    • Haz consistentes las diferentes instancias. Hubiera sido muy confuso / malo si la lista Applicative ZipList comportado como ZipList .

¿Podría alguien proporcionar un enlace a un buen estándar de codificación para Haskell? Encontré this y this , pero están lejos de ser completos. Sin mencionar que el HaskellWiki incluye tales "gemas" como "usa clases con cuidado" y "la definición de identificadores de infijo simbólicos solo debe dejarse a los escritores de la biblioteca".


Encontré un buen archivo de rebajas que cubre casi todos los aspectos del estilo del código haskell. Se puede usar como hoja de trucos. Puedes encontrarlo aquí: link



Pregunta realmente difícil. Espero que tus respuestas encuentren algo bueno. Mientras tanto, aquí hay un catálogo de errores u otras cosas molestas que he encontrado en el código para principiantes. Hay cierta superposición con la página de estilo de Cal Tech que Kornel Kisielewicz señala. Algunos de mis consejos son tan vagos e inútiles como las "gemas" de HaskellWiki, pero espero que al menos sean mejores consejos :-)

  • Formatee su código para que encaje en 80 columnas. (Los usuarios avanzados pueden preferir 87 u 88, más allá de eso está presionándolo).

  • No olvide que las ligaduras de let y las cláusulas where crean un nido recíproco de definiciones, no una secuencia de definiciones.

  • Aproveche las cláusulas where , especialmente su capacidad para ver los parámetros de función que ya están dentro del alcance (consejos vagos). Si realmente estás compartiendo Haskell, tu código debería tener mucho más en where enlaces que enlaces. Demasiadas combinaciones de let es un signo de un programador de ML no reconstruido o un programador de Lisp.

  • Evite paréntesis redundantes. Algunos lugares donde los paréntesis redundantes son particularmente ofensivos son

    • Alrededor de la condición en una expresión if (marcas como programador C no reconstruido)

    • Alrededor de una aplicación de función que es ella misma el argumento de un operador infijo (la aplicación Function se une más estrechamente que cualquier operador infijo . Este hecho debería grabarse en el cerebro de cada Haskeller, de la misma manera que los dinosaurios usamos la regla de exploración de derecha a izquierda de APL quemado en.)

  • Pon espacios alrededor de los operadores de infijo. Pon un espacio después de cada coma en un literal de tupla.

  • Prefiere un espacio entre una función y su argumento, incluso si el argumento está entre paréntesis.

  • Use el operador $ juiciosamente para reducir los paréntesis. Tenga en cuenta la estrecha relación entre $ y el infijo . :

    f $ g $ h x == (f . g . h) x == f . g . h $ x

  • No pase por alto el built-in Maybe y Either tipos.

  • Nunca escriba if <expression> then True else False ; la frase correcta es simplemente <expression> .

  • No use la head o la tail cuando pueda usar la coincidencia de patrones.

  • No pase por alto la composición de la función con el operador de punto infijo.

  • Use saltos de línea cuidadosamente. Los saltos de línea pueden aumentar la legibilidad, pero hay una compensación: su editor puede mostrar solo 40-50 líneas a la vez. Si necesita leer y comprender una función grande al mismo tiempo, no debe abusar de los saltos de línea.

  • Casi siempre prefiero los comentarios que se ejecutan al final de línea sobre los {- ... -} comentarios. Los comentarios reforzados pueden ser apropiados para encabezados grandes, eso es todo.

  • Dé a cada función de nivel superior una firma de tipo explícita.

  • Cuando sea posible, alinee -- líneas, = signos, e incluso paréntesis y comas que ocurren en líneas adyacentes.

  • Influenciado como estoy por GHC central, tengo una preferencia muy leve para usar camelCase para identificadores exportados y short_name con guiones bajos para las variables locales where -bound o let -bound.


  • Me gusta intentar organizar funciones como composiciones de estilo sin puntos tanto como sea posible haciendo cosas como:

    func = boo . boppity . bippity . snd where boo = ... boppity = ... bippity = ...

  • Me gusta usar ($) solo para evitar parens anidados o expresiones largas entre paréntesis

  • ... Pensé que tenía algunos más en mí, bueno