Legibilidad de programación funcional [cerrada]


13

Tengo curiosidad sobre esto porque recuerdo que antes de aprender cualquier lenguaje funcional, pensé que todos eran horriblemente, terriblemente, terriblemente ilegibles. Ahora que conozco a Haskell y f #, me parece que toma un poco más de tiempo leer menos código, pero ese pequeño código hace mucho más que una cantidad equivalente en un lenguaje imperativo, por lo que se siente como una ganancia neta y no estoy extremadamente practicado en funcional.

Aquí está mi pregunta, constantemente escucho de la gente de OOP que el estilo funcional es terriblemente ilegible. Tengo curiosidad si este es el caso y me estoy engañando a mí mismo, o si se tomaron el tiempo para aprender un lenguaje funcional, ¿todo el estilo ya no sería más ilegible que OOP?

¿Alguien ha visto alguna evidencia o alguna anécdota donde vio que esto iba de una manera u otra con la frecuencia suficiente para decir? Si escribir funcionalmente realmente es de menor legibilidad, entonces no quiero seguir usándolo, pero realmente no sé si ese es el caso o no ...


1
Recuerdo haber visto el código de "Super Nario Brothers" svn.coderepos.org/share/lang/haskell/nario cuando apenas sabía algo sobre programación funcional y recuerdo haber pensado 'Wow. Esto parece realmente legible '
WuHoUnited



3
@BlackICE linq y lambdas están muy lejos de definir "programación funcional". La programación funcional implica sistemas de tipos con mayor frecuencia porque cuando comienzas a reconocer funciones como tipos en lugar de solo objetos / clases / registros como tipos, terminas con muchas habilidades y técnicas nuevas. Las expresiones LINQ y Lambda (o las funciones de lista de mónada y de orden superior) son solo dos técnicas resultantes específicas, de las cuales hay muchas más.
Jimmy Hoffa

Respuestas:


15

La legibilidad del código es muy subjetiva . Debido a esto, diferentes personas considerarían que el mismo código es legible o ilegible.

Una tarea, x = x + 1suena raro para un matemático, porque una tarea se ve engañosamente similar a una comparación.

Un patrón de diseño OOP simple no sería totalmente claro para alguien que no esté familiarizado con estos patrones. Considera singleton . Alguien preguntaría "¿Por qué necesito un constructor privado? ¿Cuál es el método misterioso getInstance() ? ¿Por qué no hacemos una variable global y asignamos un objeto allí?"

Lo mismo se aplica a un código FP. A menos que conozca los patrones lógicos detrás de escena, será muy difícil incluso comprender algo muy básico, por ejemplo, cómo pasar una función como argumento a otra función.

Dicho esto, uno debe entender que FP no es una bala de plata. Hay muchas aplicaciones donde FP sería difícil de aplicar y, por lo tanto, dará lugar a un código legible peor .


Las personas deberían crear algo similar a ellos mismos (humanidad). Por ejemplo, incluso en visión por computadora tenemos redes neuronales ahora. El cuerpo humano consta de objetos, atributos, métodos y describimos otras cosas usando objetos, atributos, métodos. Entonces, la programación funcional no tiene ningún sentido
user25

12

Respuesta corta:

Uno de los elementos que hace que la gente diga que el código de programación funcional es difícil de leer es que da preferencia a una sintaxis más compacta.

Respuesta larga:

La programación funcional en sí misma no puede ser legible o ilegible, ya que es un paradigma, no un estilo de código de escritura. En C #, por ejemplo, la programación funcional se ve así:

return this.Data.Products
    .Where(c => c.IsEnabled)
    .GroupBy(c => c.Category)
    .Select(c => new PricesPerCategory(category: c.Key, minimum: c.Min(d => d.Price), maximum: c.Max(d => d.Price)));

y sería considerado legible por cualquier persona con suficiente experiencia en Java, C # o lenguajes similares.

La sintaxis del lenguaje, por otro lado, es más compacta para muchos lenguajes funcionales (incluidos Haskell y F #) en comparación con los lenguajes populares de OOP, dando preferencia a los símbolos en lugar de las palabras en inglés simple.

Esto también se aplica a los lenguajes fuera de FP. Si compara los idiomas populares de OOP con algunos menos populares que tienden a usar más palabras en inglés, los últimos se sentirían más fáciles de entender para las personas sin experiencia en programación.

Comparar:

public void IsWithinRanges<T>(T number, param Range<T>[] ranges) where T : INumeric
{
    foreach (var range in ranges)
    {
        if (number >= range.Left && number <= range.Right)
        {
            return true;
        }
    }

    return false;
}

a:

public function void IsWithinRanges
    with parameters T number, param array of (Range of T) ranges
    using generic type T
    given that T implements INumeric
{
    for each (var range in ranges)
    {
        if (number is from range.Left to range.Right)
        {
            return true;
        }
    }

    return false;
}

Del mismo modo:

var a = ((b - c) in 1..n) ? d : 0;

podría expresarse en un lenguaje imaginario como:

define variable a being equal to d if (b minus c) is between 1 and n or 0 otherwise;

Cuando una sintaxis más corta es mejor?

Si bien la sintaxis más detallada es más fácil de entender para un principiante, la sintaxis más compacta es más fácil para los desarrolladores experimentados. Un código más corto significa menos caracteres para escribir, lo que significa más productividad.

Especialmente, realmente no tiene sentido obligar a una persona a escribir una palabra clave para indicar algo que puede deducirse de la sintaxis.

Ejemplos:

  • En PHP, debe escribir functionantes de cada función o método, sin una razón específica para hacerlo.

  • Ada siempre me horrorizó por obligar a los desarrolladores a escribir muchas palabras en inglés, especialmente porque no hay un IDE correcto con autocompletado. No he usado a Ada recientemente y su tutorial oficial está caído, así que no puedo dar un ejemplo; Si alguien tiene un ejemplo, siéntase libre de modificar mi respuesta.

  • La sintaxis 1..n, utilizada en muchos FP (y Matlab), podría ser reemplazada por between 1, no between 1 and no between (1, n). La betweenpalabra clave hace que sea mucho más fácil de entender para las personas que no están familiarizadas con la sintaxis del idioma, pero aún así, dos puntos son mucho más rápidos de escribir.


8
Estoy de acuerdo con el sentimiento, pero por diferentes razones. No se trata de la facilidad con que un experto puede escribir código, ya que el código generalmente se lee con mucha más frecuencia de lo que se escribe. Un código más corto también puede ayudar a la legibilidad, al no perder tiempo, espacio de pantalla y capacidad mental si algo ya fuera obvio por un indicador más corto (por ejemplo, líneas nuevas en lugar de punto y coma, las dos coincidencias de todos modos). También puede hacer daño cuando se vuelve demasiado críptica (por ejemplo, prefiero for x in xsmás for x xs, porque me ayuda a distinguir variable de bucle y el envase).

Muchas de las personas que encuentro se quejan de FP también se quejan del fragmento de C # que mencionó como dijo, también es un ejemplo de FP. Quizás esto es más un problema de mis colegas que la legibilidad si la mayoría de las personas con OOP encuentran legible ese fragmento, aunque no estoy completamente convencido de que la mayoría de las personas con OOP lo hagan por mis experiencias ... por eso me siento tan inseguro sobre este tema.
Jimmy Hoffa

@Jimmy Hoffa: consulte programmers.stackexchange.com/a/158721/6605 donde analizo exactamente el fragmento de C # y cómo lo perciben los programadores principiantes.
Arseni Mourzenko

1
@Sergiy: en Java o C #, la firma de un método no tiene una methodpalabra clave. Ejemplo: public int ComputePrice(Product product). Agregar esa palabra clave, como lo hizo PHP, solo agrega desorden en lugar de hacer que las cosas sean más fáciles de leer. Si un programador no puede entender que una función es una función de su firma, o bien este programador no tiene experiencia alguna, o el código es mucho más ilegible que el peor código de pieza que he visto.
Arseni Mourzenko

1
@Sergiy: hay casos en los que la verbosidad puede ayudar (de lo contrario, veríamos idiomas y códigos como p i ComputePrice(product): _.unitPrice * ~.cart[_]), pero algunos idiomas lo llevan demasiado lejos. El ejemplo de la functionpalabra clave redundante en PHP es un buen ejemplo.
Arseni Mourzenko

6

Creo que una de las razones es que la programación funcional tiende a funcionar con conceptos mucho más abstractos. Esto hace que el código sea más corto y más legible para las personas que conocen y entienden los conceptos (porque expresan acertadamente la esencia del problema), pero es ilegible para las personas que no están familiarizadas con ellos.

Por ejemplo, para un programador funcional es natural escribir un código que puede fallar en diferentes puntos dentro de la Maybemónada o Eithermónada. O, para escribir un cálculo con estado con la ayuda de la Statemónada. Pero para alguien que no entiende el concepto de mónadas, todo esto parece una especie de hechicería negra.

Por lo tanto, creo que sería razonable usar fragmentos de programación funcional incluso en un equipo de personas de OOP, siempre y cuando uno use conceptos que sean fáciles de entender o aprender, como mapear una colección con una función o cierres .

(Y, por supuesto, también depende del programador que escribió algún código. Puede escribir código horriblemente ilegible en cualquier idioma, así como también puede escribir en un estilo agradable y limpio).


2

La legibilidad no tiene nada que ver con los paradigmas, modelos y demás. Mientras más código refleje la semántica de su dominio problemático, cuanto más opere una terminología y modismos de dicho dominio problemático, más legible será.

Esta es la razón por la cual el código OOP no es tan legible en absoluto: no es que muchos problemas del mundo real se expresen naturalmente en términos de taxonomías jerárquicas. Los objetos que se pasan mensajes entre sí es un concepto extraño, y está muy lejos de cualquier cosa "real". Sorprendentemente, hay muchos más conceptos del mundo real que pueden asignarse naturalmente a los modismos funcionales. Los problemas tienden a definirse de manera declarativa, por lo tanto, una solución declarativa es más natural.

Sin embargo, hay muchas otras semánticas que podrían estar más cerca del mundo real que una POO pura y funcional, un flujo de datos puro o lo que sea que sea. Y debido a este hecho, un enfoque orientado al lenguaje para la resolución de problemas produce el código más legible, superando todos los paradigmas "puros" existentes. Con los lenguajes específicos del dominio, cada problema se expresa en su propia terminología natural. Y los lenguajes funcionales son un poco mejores que las cosas principales de OOP para facilitar la implementación de DSL (aunque hay enfoques mucho mejores disponibles).


1

La legibilidad del código es subjetiva. Estoy seguro de que algunas personas lo critican por falta de comprensión. Existen modismos naturalmente diferentes en la forma en que se implementan los patrones comunes. Por ejemplo, el patrón Visitante realmente no tiene sentido en un idioma con coincidencia de patrones .

La inferencia de tipos puede ser una característica difícil. Por lo general, es un gran acelerador del desarrollo, sin embargo, a veces puede ser difícil determinar qué tipos están involucrados debido a la falta de contexto que conduce a errores confusos. Esto no se limita a los lenguajes de programación funcional: ¡también lo he visto en las plantillas de C ++!

Los lenguajes modernos tienden a ser multi-paradigmáticos . Esto incluye C # y F #. Es posible escribir un estilo funcional en C # y un estilo imperativo en F #. Las mismas personas que critican los lenguajes funcionales probablemente escriben código funcional en su lenguaje orientado a objetos.

El desarrollo comercial en lenguajes funcionales todavía es relativamente inmaduro. He visto una serie de errores cometidos que se considerarían una mala forma en cualquier idioma. Como:

  1. Cambiar el estilo a medida que aprende el idioma (y no refactorizar) lo que lleva a una inconsistencia.
  2. Demasiado en un archivo.
  3. Demasiadas declaraciones en una línea.

Con respecto a los errores, también agregaría: 4. Uso excesivo de símbolos, por ejemplo: ~ @ # $% ^ & * () -_ + = \ | /.,; 5. Características implícitas: declaraciones / palabras clave / declaraciones opcionales, conversiones implícitas, etc .;
Sergiy Sokolenko
Al usar nuestro sitio, usted reconoce que ha leído y comprende nuestra Política de Cookies y Política de Privacidad.
Licensed under cc by-sa 3.0 with attribution required.