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
, entoncesjoin
hace eso, entre otras cosas.
- Muchas veces las funciones de biblioteca existentes son más generales de lo que uno iba a hacer. Por ejemplo, si quieres
- 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.
- Para una función como
- 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 llamawhere
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 estiloApplicative
conZipList
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 deFunctor
).
- 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 comojoin :: Monad m => m (ma) -> ma
. Hay menos margen de error al programar lajoin
porque cuando se programaconcat
puede revertir las listas por error y aljoin
hay muy pocas cosas que puede hacer.
- Por ejemplo, si desea programar
- 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 comoZipList
.
¿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
Sugeriría echar un vistazo a este inspector de estilo .
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áusulaswhere
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 enwhere
enlaces que enlaces. Demasiadas combinaciones delet
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
yEither
tipos.Nunca escriba
if <expression> then True else False
; la frase correcta es simplemente<expression>
.No use la
head
o latail
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 yshort_name
con guiones bajos para las variables localeswhere
-bound olet
-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