¿La programación funcional agrega complejidad en el código? [cerrado]

17

Durante todo el año pasado he escrito código Scala (proveniente de un fondo Java). Realmente me gustó cómo podría crear un código más simple y limpio, con vals, clases de casos, funciones de mapa / filtro / lambda, implicidades y la inferencia de tipos. Lo he usado principalmente para una aplicación basada en Akka .

Este año estoy en un proyecto Scala con un nuevo equipo, a quien realmente le gusta la programación funcional. Usan mucho Scalaz , y el código está lleno en todas partes con solicitantes, límites de contexto, mónada de lector / escritor / estado, incluso el método principal está "envuelto" en una mónada de E / S. Su razonamiento es que esto hace que el compilador "trabaje para nosotros" al afirmar que el código es correcto y que cada función está libre de efectos secundarios.

Aun así, desde mi punto de vista, toda esta sintaxis realmente se interpone en el camino de la lógica empresarial. Por ejemplo, un tipo de "MyBusinessObject" está bien, al igual que tipos como "List [MyBusinessObject]", "Option [MyBusinessObject]" o incluso "Future [MyBusinessObject]". Todos tienen un significado y un propósito claros. Por otro lado, código como:

def method[M[_]: Applicative] = {
  case (a, b) => (ca[M](a) |@| cb[M](b)) {
    case t @ (ra, rb) =>
      if (ra.result && rb.result) t.right
      else t.left
  }
}

¿Le agrega complejidad al programa o soy yo el único que no estoy acostumbrado a esta forma de programación?

Luciano
fuente
66
¿Cuál es su pregunta objetivamente responsable?
Deer Hunter
1
Parece que conduce a una tonelada de código con nombres de variables de una o dos letras. Parece un poco APL. Eso no es un complemento.
user949300
3
Empecé a jugar con Haskell el año pasado. Parecía increíblemente complejo en ese momento, cuando no entendía conceptos como curry, functors, mónadas, etc. Haskell es similar a Scalaz en que tiene muchas funciones simbólicas cortas, como >>=y <$>, que no significan nada hasta que saber lo que hacen Sin embargo, después de aprender lo que significan, ahora me leen muy natural y rápidamente. Realmente no es una respuesta, solo mi experiencia objetiva con cosas como esta. También uso Scala, pero no tengo experiencia con la biblioteca Scalaz.
KChaloux
3
Simplemente no estás familiarizado con los modismos. @ user949300 las variables cortas no son realmente un problema para muchos códigos funcionales (¡piense en las convenciones de estilo matemático!). También lea el blog de Tony Morris para una discusión más profunda de lo que mejor transmite significado, tipos o nombres de variables verbosas.
Andres F.
3
@ user949300: los nombres cortos de variables se prefieren localmente, eso es lo mismo en los mundos funcionales e imperativos (no escribiría for(i=0; i<7; ++i) { trivialOperation(i); }con alguna trivialOperationCountvariable incómoda , ¿verdad?) Ahora, los lenguajes de programación funcionales con coincidencia de patrones a veces introducirán algunas variables más donde simplemente escribiría llamadas al método de acceso en OO. El resultado es generalmente más conciso; quizás un poco menos autoexplicativo, pero buscar la declaración de datos normalmente lo deja claro rápidamente. La escritura estática ayuda mucho, no es como en APL.
Leftaroundabout

Respuestas:

37

Esto no tiene nada que ver con la programación funcional: puede encontrar este tipo de situación en el contexto de cualquier otro lenguaje de programación: los desarrolladores que aman tanto las construcciones avanzadas de "su" lenguaje que ignoran cualquier sentido común sobre la legibilidad y mantener las cosas simples. Me he encontrado con tal situación en C, C ++, Perl, Java, C #, Basic y otros lenguajes no funcionales. No es la programación funcional lo que agrega complejidad al código, como hacen los programadores.

No me malinterpreten, no recomiendo evitar las funciones avanzadas de lenguaje, pero es importante encontrar el equilibrio adecuado en el contexto dado. Al escribir una biblioteca genérica para el uso de> 100,000 desarrolladores en todo el mundo, existen diferentes medidas para aplicar, como cuando se escribe un generador de informes individual solo para su oficina local.

Doc Brown
fuente
77
También tiene mucho que ver con la comunidad. Para un desarrollador con experiencia en Java o C #, el código es apenas comprensible (y su comunidad tampoco lo entendería). Pero si escribe Haskell, por ejemplo, y no usa mónadas, solicitantes, functors, etc., está desconcertando a la comunidad de ese idioma. La "naturalidad" del código no es inherente, sino relativa a su comunidad y prácticas establecidas.
Andres F.
1
Esto es difícil de ver porque la mayoría de nosotros proviene de entornos imperativos, lo que a veces nos lleva a hacer suposiciones equivocadas sobre lo que es natural.
Andres F.
solo mire la biblioteca SLT C ++, que podría escribirse para que sea mucho más legible para el aficionado
fanático del trinquete el
@ratchetfreak: Supongo que te refieres a STL. Creo que este es un muy buen ejemplo (y de hecho, tuve esto en mente en mi respuesta). El uso de meta programación de plantillas tiene mucho sentido cuando eres un programador de STL, porque hace que el STL sea más reutilizable. Y las personas que tienen que mantener ese código normalmente también se usan para la metaprogramación de plantillas. El uso de la metaprogramación de plantillas de forma similar a STL en toda su aplicación comercial estándar puede conducir fácilmente a un código complicado y difícil de mantener. Seguramente se pueden encontrar casos (raros) en los que TMP está bien incluso en aplicaciones comerciales, por supuesto.
Doc Brown
@DocBrown, sí, la dislexia comenzó en el momento equivocado, pero honestamente, si tuviera muchas ganas (y mucho más tiempo del que tengo ahora), podría reescribir muchos de los cuerpos funcionales para que sean mucho más legibles.
Ratchet Freak
7

Yo diría que no estás acostumbrado a la forma en que codifican es al menos parte de la imagen. Estoy en una situación similar a la tuya (viniendo de C # a F # y trabajando con personas con antecedentes de Haskell), y aunque me parece una experiencia interesante, tengo momentos en los que me golpeo la cabeza contra la pared, desenredando un composición de funciones sin puntos particularmente enrevesada solo para familiarizarse con lo que está sucediendo allí. Es una cosa cultural.

En cuanto a si este código en particular agrega complejidad al programa, no lo sé. Convino en que un código genérico puede ser complejo en sí mismo. Pero es una utilidad, no una parte de la lógica empresarial. Si desea saber si hace que la base de código sea más compleja o más simple, tendrá que imaginar cómo debería verse sin ese fragmento de código. A menudo es el caso con construcciones tan genéricas que son complejas en sí mismas, pero es una complejidad que puede caber en una sola pantalla. Al mismo tiempo, hacen que toda la base de código sea un poco más simple. Este es particularmente el caso de las mónadas.

Por otra parte, también puede ser un caso de 'arte por el arte', como sugiere @Doc Brown. No puedo descartarlo tampoco.

scrwtp
fuente
5

Yo diría que, en general, la programación funcional reduce la complejidad al eliminar el estado mutable, reduciendo así el número de casos que deben considerarse al tratar de comprender cómo funciona una sección de código.

Sin embargo, la programación funcional hace posible mayores grados de abstracción, y aunque el código altamente abstracto puede ser extremadamente útil, también puede ser difícil de entender porque, por definición, está separado del contexto que normalmente usaría para guiar su comprensión. Su comentario "Todos tienen un significado y un propósito claros" sobre los objetos comerciales es indudablemente cierto, pero en realidad es un reflejo del hecho de que esa lógica es muy específica para una necesidad y un contexto que ya comprende. La existencia de una construcción como Monad le permite hacer algo muy útil con poco esfuerzo, pero la web está llena de páginas que intentan explicar qué es una Monad. Eso es abstracción para ti.

Además, Scalaz fue escrito por personas que habían estado comiendo y respirando FP durante mucho tiempo; querían llevar la funcionalidad disponible en Haskell a Scala. Al hacerlo, no intentaron ser pedagógicos. Scalaz utiliza un vocabulario y un estilo que parecen claros y directos para los autores pero ajenos a los no iniciados. Los métodos que son desconcertantes para el resto de nosotros parecían tan obvios para los autores, dados sus antecedentes de Haskell, que ni siquiera justificaron un comentario.

Además, como lenguaje de programación funcional, Scala tiene algunas deficiencias (en parte porque la JVM tiene deficiencias) que obligaron a los autores de Scalaz a escribir código más feo en algunos casos. Por ejemplo, la falta de eliminación general de llamadas de cola obliga al uso de trampolines en algún código, y la falta de un "sistema amable" puede complicar las firmas de tipo.

Y finalmente, Scalaz hace un gran uso de sí mismo. Eso podría considerarse como un signo de su poder, pero para los no iniciados puede hacer que la fuente sea un rompecabezas: cualquier pieza aleatoria de código que mires probablemente haga uso de otra cosa que te parezca ajena.

Cuelga ahí. Y esto podría ayudar.

AmigoNico
fuente
-4

¿Agrega complejidad al programa, o es solo que no estás acostumbrado a esta forma de programación?

¿Por qué crees que estas posibilidades no son lo mismo?

El código bien escrito puede ser leído por personas que no están familiarizadas con el lenguaje de programación específico. Algunos idiomas (BÁSICO, Pascal, etc.) pueden ser leídos y entendidos por escolares que nunca antes han visto ningún lenguaje de programación.

Si alguien que tiene experiencia con otros idiomas y experiencia con Scala (y que supongo que ha trabajado con Scalaz durante al menos una semana y tiene colegas para explicar las cosas más difíciles) todavía está confundido; entonces eso es prueba de que ha agregado complejidad.

Brendan
fuente
11
Esto simplemente no es cierto:"Well written code can be read by people who aren't familiar with the specific programming language."
Andres F.
@ Andreas: Es cierto ... hasta cierto punto. El código bien escrito separará la lógica empresarial de los detalles de implementación, y la lógica empresarial debería ser legible, porque la mayor parte de lo que está haciendo es hacer llamadas directas a funciones auxiliares bien nombradas. Esos ayudantes pueden usar todo tipo de características del lenguaje, por supuesto, y requieren una gran experiencia con el idioma y las bibliotecas para comprender.
Ben Voigt
44
Creo que la siguiente es APL idiomática: x[⍋x←6?40]. ¿Qué crees que hace? Seguro que no lo habría sabido ...
bdesham
3
@Brendan Solo dentro del mismo paradigma (e incluso entonces, a veces no). Por ejemplo, Prolog, Java y APL son tan diferentes que diría que si solo conoces uno de esos (y no otros idiomas), no puedes leer los otros dos, no importa qué tan bien conozcas el primero. (En serio, en el ejemplo de Bdesham, ¿cómo demonios se supone que debes interpretar el "árbol de Navidad" si no conoces ninguna APL?)
Izkata
1
Brendan, tu definición de bien escrito no es estándar. Bien escrito siempre es relativo al idioma y su comunidad. Un programa en lenguaje X está bien escrito si no tiene errores, es eficiente y claro ... ¡para la audiencia dada! Esto se aplica al lenguaje escrito en general, por cierto: siempre conozca a su audiencia. Lo que es adecuado para (digamos) un artículo científico probablemente no sea adecuado para un correo electrónico a su madre.
Andres F.