haskell - online - programacion funcional ventajas y desventajas
¿La programación funcional exige nuevas convenciones de nomenclatura? (10)
Recientemente comencé a estudiar programación funcional usando Haskell y encontré este artículo en la wiki oficial de Haskell: Cómo leer a Haskell .
El artículo afirma que los nombres cortos de variables como x
, xs
f
son adecuados para el código Haskell, debido a la concisión y la abstracción. En esencia, afirma que la programación funcional es un paradigma tan distinto que las convenciones de nomenclatura de otros paradigmas no se aplican.
¿Cuáles son sus pensamientos sobre esto?
Acabo de asistir a una serie de charlas sobre Haskell con muchas muestras de código. Siempre que el código tratara con x, i y f, la denominación no me molestaba. Sin embargo, tan pronto como entramos en la manipulación de la lista de trabajo pesado y similares encontré las tres letras o menos nombres para ser mucho menos legibles de lo que prefiero.
Para ser justos, una parte importante de la denominación siguió una serie de convenciones, así que supongo que una vez que entres en la jerga será un poco más fácil.
Afortunadamente, nada nos impide usar nombres significativos, pero no estoy de acuerdo con que el lenguaje de alguna manera haga que los identificadores de tres letras sean significativos para la mayoría de las personas.
Creo que el alcance es la razón número 1 para esto. En los lenguajes imperativos, las variables dinámicas, especialmente las globales, deben nombrarse correctamente, ya que se usan en varias funciones. Con el alcance léxico, está claro a qué está vinculado el símbolo en tiempo de compilación.
La inmutabilidad también contribuye a esto en cierta medida: en las lenguas tradicionales como C / C ++ / Java, una variable puede representar datos diferentes en diferentes momentos. Por lo tanto, debe tener un nombre para darle al programador una idea de su funcionalidad.
Personalmente, creo que las características características como funciones de primera clase hacen que los nombres de símbolos sean bastante redundantes. En los idiomas tradicionales, es más fácil relacionarse con un símbolo; en función de su uso, podemos decir si se trata de datos o una función.
Creo que si la semántica de los argumentos es clara dentro del contexto del código, entonces puede salirse con la suya con nombres cortos de variables. A menudo los uso en C # lambdas por la misma razón. Sin embargo, si es ambiguo, debería ser más explícito al nombrar.
map :: (a->b) -> [a] -> [b]
map f [] = []
map f (x:xs) = f x : map f xs
Para alguien que no ha tenido ninguna exposición a Haskell, podría parecer un código feo e inmanejable. Pero la mayoría de los programadores de Haskell entenderán esto de inmediato. Entonces hace el trabajo.
var list = new int[] { 1, 2, 3, 4, 5 };
int countEven = list.Count(n => n % 2 == 0)
En ese caso, el nombre corto de la variable parece apropiado.
list.Aggregate(0, (total, value) => total += value);
Pero en este caso parece más apropiado nombrar las variables, porque no es inmediatamente evidente lo que está haciendo el Agregado.
Básicamente, creo que no debemos preocuparnos demasiado por las convenciones a menos que sea absolutamente necesario para evitar que la gente se joda. Si tiene alguna opción en el asunto, use lo que tenga sentido en el contexto (idioma, equipo, bloque de código) en el que está trabajando, y será comprensible para otra persona que lo lea horas, semanas o años después. Cualquier otra cosa es solo un TOC que desperdicia tiempo.
Cualquier cosa que ayude a la legibilidad es algo bueno; por lo tanto, los nombres significativos son algo bueno en cualquier idioma.
Utilizo nombres cortos de variables en muchos idiomas, pero están reservados para cosas que no son importantes en el significado general del código o donde el significado es claro en el contexto.
Sería cuidadoso de cuán lejos tomé el consejo sobre los nombres de Haskell
En Haskell, el significado se transmite menos con nombres de variables que con tipos . Ser puramente funcional tiene la ventaja de poder solicitar el tipo de cualquier expresión, independientemente del contexto.
En un paradigma de programación funcional, las personas generalmente construyen abstracciones no solo de arriba hacia abajo , sino también de bottom-up . Eso significa que básicamente mejora el idioma del servidor. En este tipo de situaciones, veo nombres terminados según corresponda. El lenguaje Haskell ya es escueto y expresivo, por lo que deberías estar acostumbrado.
Sin embargo, cuando intento modelar un dominio determinado, no creo que los nombres sucintos sean buenos, incluso cuando los cuerpos funcionales son pequeños. El conocimiento del dominio debe reflejarse al nombrar.
Solo es mi opinión.
En respuesta a tu comentario
Tomaré dos fragmentos de código de Real World Haskell , ambos del capítulo 3 .
En la sección llamada " Un enfoque más controlado ", los autores presentan una función que devuelve el segundo elemento de una lista. Su versión final es esta:
tidySecond :: [a] -> Maybe a
tidySecond (_:x:_) = Just x
tidySecond _ = Nothing
La función es lo suficientemente genérica, debido al parámetro de tipo a
y al hecho de que estamos actuando sobre un tipo integrado, por lo que realmente no nos importa qué es realmente el segundo elemento. Creo que x
es suficiente en este caso. Al igual que en una pequeña ecuación matemática.
Por otro lado, en la sección denominada " Introducción de variables locales ", están escribiendo una función de ejemplo que intenta modelar una pequeña parte del dominio bancario:
lend amount balance = let reserve = 100
newBalance = balance - amount
in if balance < reserve
then Nothing
else Just newBalance
Aquí no se recomienda el uso de un nombre corto de variable. Realmente nos importa lo que representan esas cantidades.
Estoy de acuerdo con muchos de los puntos que aquí se hacen sobre la asignación de argumentos, pero una rápida ''búsqueda en la página'' muestra que nadie ha mencionado la programación tácita (alias pointfree / sin sentido). Si esto es más fácil de leer puede ser discutible por lo que depende de usted y su equipo, pero definitivamente vale la pena una consideración a fondo.
Sin argumentos con nombre = Sin convenciones de nomenclatura de argumentos.
Estoy estudiando Haskell ahora, pero no creo que sus convenciones de nombres sean tan diferentes. Por supuesto, en Java es difícil encontrar nombres como xs
. Pero es fácil encontrar nombres como x
en algunas funciones matemáticas, i
, j
para contadores, etc. Considero que estos nombres son perfectamente apropiados en el contexto correcto. xs
en Haskell es apropiado solo funciones genéricas sobre listas. Hay muchos de ellos en Haskell, por lo que este nombre es muy común. Java no proporciona una manera fácil de manejar tales abstracciones genéricas, por eso los nombres de las listas (y las listas mismas) suelen ser mucho más específicas, por ejemplo, lists
o users
.
Mi práctica de Haskell es solo de nivel mediocre, por lo tanto, me atrevo a tratar de responder solo la segunda parte más general de tu pregunta:
" En esencia, afirma que la programación funcional es un paradigma tan distinto que las convenciones de nomenclatura de otros paradigmas no se aplican " .
Sospecho que la respuesta es "sí", pero mi motivación detrás de esta opinión está restringida solo a la experiencia en un solo lenguaje funcional. Aún así, puede ser interesante, porque es extremadamente minimalista, por lo tanto, teóricamente muy "puro", y subyacente en muchos lenguajes funcionales prácticos.
Era curioso lo fácil que es escribir programas prácticos sobre un lenguaje de programación funcional "extremadamente" minimalista como la lógica combinatoria .
Por supuesto, los lenguajes de programación funcionales carecen de variables mutables, pero la lógica combinatoria "va un paso más allá" y carece incluso de parámetros formales. Carece de azúcar sintáctico, carece de cualquier tipo de datos predefinidos, incluso booleanos o números. Todo debe ser imitado por los combinadores, y se remonta a las aplicaciones de solo dos combinadores básicos.
A pesar del minimalismo extremo, todavía hay métodos prácticos para "programar" la lógica combinatoria de una manera limpia y agradable. He escrito un quine en él de una manera modular y reutilizable, y no sería desagradable ni siquiera bootstrap un self-interpreter en él.
Para resumen, sentí las siguientes características al usar este lenguaje de programación funcional extremadamente minimalista:
Hay una necesidad de inventar muchas funciones auxiliares. En Haskell, hay una gran cantidad de azúcar sintáctica (coincidencia de patrones, parámetros formales). Puede escribir funciones bastante complicadas en pocas líneas. Pero en lógica combinatoria, una tarea que podría expresarse en Haskell por una sola función, debe ser reemplazada por funciones auxiliares bien elegidas. La carga de reemplazar el azúcar sintáctico Haskell es tomada por funciones auxiliares hábilmente elegidas en la lógica combinatoria. En cuanto a responder a su pregunta original: vale la pena inventar nombres significativos y pegadizos para estas legiones de funciones auxiliares, porque pueden ser bastante poderosas y reutilizables en muchos contextos adicionales , a veces de forma inesperada .
Además, un programador de lógica combinatoria no solo se ve obligado a encontrar nombres atractivos de un grupo de funciones auxiliares hábilmente elegidas, sino que se ve obligado a (re) inventar nuevas teorías . Por ejemplo, para imitar listas , el programador se ve obligado a imitarlas con sus funciones de fold , básicamente, tiene que (re) inventar catamorfismos, conceptos algebraicos profundos y teoría de categorías.
Conjeturo, varias diferencias se remontan al hecho de que los lenguajes funcionales tienen un poderoso "pegamento" .
Cuando fueres haz lo que vieres
(O como dicen en mi pueblo: "Donde fueres, haz lo que vieres")