¿La programación funcional es simplemente diferente o es realmente más difícil?

12

¿La programación funcional es simplemente diferente o es realmente más difícil ?

Digamos a alguien que nunca antes había aprendido programación, y se le enseña programación funcional. vs alguien que nunca antes había aprendido programación, y se le enseña la programación imperativa. ¿Cuál le resultará más difícil? o lo mismo?

Mi pregunta: digamos que el problema ahora es camello una entrada,

tal que se qwe_asd_zxc_rty_fgh_vbnconvierteqweAsdZxcRtyFghVbn

La forma de procedimiento es:

  1. dividirlo a lo largo del _
  2. recorrer el conjunto omitiendo el primer elemento
  3. para cada entrada capitalizamos la primera letra
  4. une los resultados juntos

La forma funcional es:

  1. si no puede encontrar la _devolucióninput
  2. cortar a lo inputlargo de la primera _(de modo que obtengamos qwey asd_zxc_rty_gfh_cvb)
  3. poner en mayúscula la primera letra de heady concat que conf(tail)

Ok, si tiene antecedentes funcionales Y tiene una experiencia sustancial en programación de procedimientos, me gustaría preguntar: ¿le tomará más tiempo descubrir la forma de procedimiento o le tomará más tiempo descubrir la forma funcional?

Si tiene antecedentes procesales pero tiene muchos años de experiencia con la programación funcional, me gustaría hacerle la misma pregunta: ¿le tomará más tiempo descubrir la forma procesal o le tomará más tiempo descubrir la funcionalidad? ¿camino?

Pacerier
fuente
55
Ehrm, la "forma de procedimiento" me parece perfectamente funcional si la utilizamos mappara el paso 3 en lugar de un bucle mutante. El segundo enfoque es algo que solo consideraría si no hay una función dividida en la biblioteca estándar (en cuyo caso debe compararse con una solución imperativa que tampoco se usa split).
sepp2k
8
No hay nada específicamente funcional o de procedimiento en ninguno de sus ejemplos. Me parece que estás tratando de extrapolar de una comprensión defectuosa de la programación funcional. No es de extrañar que esté obteniendo resultados inusuales.
Rein Henrichs
No creo que la programación funcional sea difícil, simplemente es diferente. Si no tiene experiencia en programación, tampoco es tan fácil de aprender, pero por alguna razón, una vez que aprende la programación imperativa, la programación funcional se vuelve difícil.
dan_waterworth
1
Creo que la distinción entre funcional y de procedimiento se vuelve discutible, ya que los lenguajes principales como JavaScript, C #, Groovy contienen más y más funciones funcionales.
user281377
2
La programación imperativa es mucho más difícil y contra intuitiva para aquellos que no tenían experiencia previa en programación. Una expresión como x=x+1puede hacer explotar un cerebro inesperado. La programación funcional es natural, no es más que funciones estrictamente matemáticas puras y convenientes.
SK-logic

Respuestas:

12

Sólo diferente. La programación funcional está mucho más relacionada con las matemáticas, con lo que la mayoría de la gente está familiarizada. Todo el asunto de las "variables inmutables" solo impacta a los programadores imperativos donde la mentalidad "mutable" está profundamente arraigada.

Para los recién llegados, a menudo es bastante intuitivo que no se puede cambiar el valor de algo.

Cuando estudié CS, nos enseñaron un lenguaje funcional como nuestro primer curso. Y todos los que aprendieron C ++ o Java lucharon anteriormente. Aquellos que eran nuevos en la programación lo captaron con bastante facilidad.

jalf
fuente
¿Eres uno de esos nuevos en la programación y lo aprendiste con bastante facilidad?
Pacerier
Estaba en algún punto intermedio. Había hurgado un poco con C ++ y algunos PHP antes de eso, pero no lo suficiente como para acostumbrarme realmente a la mentalidad imperativa. El patrón era bastante claro cuando mirabas a la clase en su conjunto. Además, esto fue hace casi una década, así que no, no soy muy nuevo en programación hoy;)
jalf
Variables inmutables? ¿No es Mathica un lenguaje de programación funcional? las variables en matemática son seguramente mutables, ¿no?
user56834
20

Es diferente

Cuando programa, traduce esencialmente la forma en que razona en código, se puede decir que la distancia entre sus pensamientos y la solución final es la "brecha cognitiva". Cuanto más grande sea la brecha, más difícil será cerrarla.

Si proviene de un entorno de procedimiento, se habrá entrenado para pensar de manera procesal, por lo que la brecha será menor que para el código funcional, y viceversa.

La única forma de que un paradigma de programación sea intrínsecamente más fácil que cualquier otra cosa sería si se asigna a algo que ya sabía, como el lenguaje ordinario, por lo que comenzaría con un espacio más corto.

Funcional y procesal es un concepto bastante fluido de todos modos y tienden a superponerse

Homde
fuente
4

Sí, la programación funcional tiende a ser difícil de comprender para muchas personas (tiendo a decir, especialmente aquellos que ya han estado expuestos a la programación de procedimientos primero).

También diría que su ejemplo de programación funcional no es realmente un muy buen ejemplo de programación funcional. Está usando la recursión y solo componiendo un resultado en lugar de modificar el estado, pero no mucho más que eso.

Para obtener un mejor ejemplo de programación funcional, considere un problema más general: en lugar de "buscar un guión bajo y convertir la siguiente letra a mayúscula", considere esto como solo un caso especial de buscar un patrón y ejecutar algún código arbitrario cuando se encuentra

Muchos lenguajes lo admiten, pero para hacerlo requieren que especifiquemos el patrón como algo así como una expresión regular. Sin embargo, las expresiones regulares no son más o menos que un lenguaje de programación de propósito especial, y una implementación RE es un compilador y / o intérprete para ese lenguaje. El resultado de compilar el RE es básicamente una función que se ejecuta (en una máquina virtual RE especial) para hacer coincidir la expresión con alguna entrada.

En algo como Perl, usa un lenguaje especial para especificar el patrón, y un compilador especial para convertir esa cadena en algún tipo de función, y un intérprete especial para tomar esa función y ejecutarla. En un lenguaje funcional, normalmente usaría el lenguaje en sí para especificar el patrón, y usaría el compilador propio del lenguaje para producir una función real . Podemos generar esa función sobre la marcha (como si pudiéramos compilar un RE cuando queramos), pero cuando lo hacemos, el resultado puede ejecutarse como cualquier otra función en el lenguaje en lugar de necesitar cosas especiales de RE para hacerlo.

El resultado es que nosotros podemos generalizar el problema anterior con relativa facilidad. Sin embargo, en lugar de codificar el '_' y la "mayúscula" directamente en la transformación, podemos tener algo como:

s&r(pattern, transform, string) {
    if (!pattern(string))
        return string
    else
        return transform(matched part of string) + s&r(rest of string);
}

Pero, a diferencia de algo en lo que especificamos el patrón como un RE, podemos especificar el patrón directamente como una función real, y aún usarlo, algo así como:

my_pattern(string) return beginning(string) == '_';

Y luego pasamos esa función al s & r. En este momento, es una función bastante trivial, y la hemos codificado completamente estáticamente. Un lenguaje funcional se vuelve en gran medida interesante cuando lo usamos como si pudiéramos REs, y generamos una función completamente nueva sobre la marcha basada en algo como la entrada del usuario, pero a diferencia de un RE, esa función no necesita un intérprete RE especial para funcionar: es solo una función normal como cualquier otra.

Jerry Coffin
fuente
4

Aquí está el código completo en Racket :

;; camelize : string -> string
(define (camelize str)
  (let ([parts (regexp-split #rx"_" str)])
    ;; result of regexp-split is never empty
    (apply string-append
           (first parts)
           (map string-titlecase (rest parts)))))

(camelize "qwe_asd_zxc_rty_fgh_vbn")
;; => "qweAsdZxcRtyFghVbn"

Como programador funcional con experiencia en procedimientos, no creo que me lleve más tiempo "encontrar" una solución de procedimiento, pero ciertamente me tomaría más tiempo escribirlo.

Por cierto, el resultado esperado del ejemplo en la publicación original es incorrecto: le falta una "h" cerca del final.

Ryan Culpepper
fuente
Dios por señalar eso. editado
Pacerier
3

Mi teoría favorita es que los modelos de programación son más fáciles de entender cuanto más cerca estén del funcionamiento real de las computadoras. Los punteros son difíciles de entender hasta que te das cuenta de que son esencialmente direcciones de máquina. La recursión es difícil de entender hasta que haya dado un paso consciente a través de un pequeño ejemplo, haya visto los cuadros de la pila y se haya dado cuenta de dónde se almacenan los diferentes valores de la misma variable. Eso no significa que la programación del ensamblador sea más fácil que la programación de alto nivel, pero haber visto cómo se hace hace maravillas para el modelo mental que es clave para la competencia, ya sea en la programación o en la usabilidad general.

Ahora, el modelo de procedimiento está algo más cerca de la arquitectura de máquina habitual: las asignaciones son escrituras de memoria (o registro). Las llamadas a procedimientos son realmente saltos de fantasía, un en ifrealidad es un salto condicional, etc. Pero en Lisp, por ejemplo, no existe un simple equivalente de bajo nivel para un enlace léxico o una expresión lambda. Comprenderlo requiere que imagines una máquina funcional abstracta completamente separada entre el nivel del lenguaje y la máquina física, porque aparentemente, la mayoría de las personas nunca llegan tan lejos.

( Estoy familiarizado con la idea de que la arquitectura de von Neumann es en última instancia arbitraria, y no debemos perjudicar las mentes de los principiantes con detalles tan irrelevantes de la arquitectura de la máquina, y en su lugar presentarles directamente la semántica de los lenguajes de programación. De hecho, he enseñé algunos de estos cursos yo mismo. Pero cada vez más siento que este es un objetivo noble pero equivocado; las personas aprenden a programar construyendo la comprensión de abajo hacia arriba, y el camino hacia la programación funcional es simplemente un poco más largo).

Kilian Foth
fuente
77
Según esa lógica, Assembler debería ser el más fácil de todos los idiomas para aprender :)
Homde
44
La programación funcional es bastante fácil de entender si se llega desde la dirección correcta. La "máquina funcional abstracta" que mencionas es simplemente álgebra . La evaluación se realiza mediante reescritura de términos; La aplicación de la función se realiza por sustitución. Los programadores aprenden a resolver problemas usando las mismas herramientas que ya han visto en años de clases de matemáticas. Si persiguen CS, hay tiempo suficiente para encontrarse con la pila de tortugas más tarde; si no, todavía han aprendido habilidades útiles para resolver problemas y principios de diseño. Echa un vistazo a Cómo diseñar programas .
Ryan Culpepper
2
@mko No, según esta lógica, los códigos de bytes reales 011011001001101...serían el idioma más fácil de aprender.
MarkJ
2
@konrad: el ensamblador RISC ES probablemente el lenguaje más fácil de aprender. Saber cómo hacer que haga algo útil es otra historia completa ...
Bryan Boettcher