Entrada/salida en lenguajes de programación 'matemáticos' [cerrado]

Más de una vez he observado esto: Una persona describe un lenguaje de programación funcional (a diferencia de un lenguaje de programación que hace un uso intensivo de estados intercalados), esa persona dirá que es muy matemático, entonces debemos usar el lenguaje de las matemáticas; luego, para demostrar, comienza, "Digamos que tenemos una función f que toma la entrada x y da la salida y..." o algo así.

Esto me molesta porque nunca escuché a un matemático describir una función como tomando entradas y dando salidas. En cambio, creo que una función se considera como un mapa, y podría decirse que el dominio, el mapa y el codominio existen al mismo tiempo.

En el mundo del procesamiento informático, se suele asociar una determinada duración con una operación, pero no tiene por qué ser así: podría ser que la representación del lenguaje no represente realmente la operación directamente (la función podría incluso eliminarse por completo con la función). compilador o intérprete de código), o tal vez la función en realidad toma una entrada diferente de lo que se pensaba, se distribuye entre muchos procesadores, etc. En resumen, las operaciones de la máquina no están necesariamente representadas de una manera sencilla para la interpretación humana por el lenguaje de programación. .

Además, el tiempo de la operación puede ser insignificante, puede ejecutarse en paralelo con otra operación o los pasos de un programa pueden ejecutarse en una secuencia diferente. Incluso podría requerir algunas otras operaciones posteriores que no sean obvias para el observador, por lo que podría tener una influencia en otros puntos en el tiempo.

Sin embargo, creo que existe un conflicto más fundamental posible. Como expresa Schopenhauer en 'La raíz cuádruple', existe un problema al aplicar el concepto de 'causalidad' en el sentido físico a la metáfora de la 'causalidad' lógica.

El procesamiento informático parece estar justo en el espacio entre la 'inferencia como modelo físico' y la 'inferencia como modelo lógico'. ¿Es este un problema fundamental como lo he expresado? ¿Es posible que estas metáforas mixtas se vuelvan más problemáticas a medida que avanza el campo del procesamiento de datos?

Si bien veo párrafos y formato (lo cual es una buena señal), no veo dónde está la pregunta de filosofía . Sin embargo, veo muchas afirmaciones sobre la informática. ¿Podría resaltar de alguna manera la pregunta que está haciendo aquí?
¡Bienvenidos a Filosofía! Esto se lee más como una respuesta que como una pregunta: ¿hay alguna posibilidad de que puedas tratar de especificar un poco más explícitamente cuál es exactamente el problema que estás encontrando en tu estudio de filosofía? ¿Cómo se ve en tu mente una respuesta a esta pregunta? ¿Qué es exactamente lo que le gustaría que alguien aquí le explicara (en unos pocos párrafos)?
¡Hola gracias! Quizás mi pregunta fue más una respuesta que una pregunta, y quizás un poco amplia. Realmente esperaba expandir mis estudios obteniendo una referencia en filosofía o historia en una respuesta. La respuesta de @CortAmmon fue buena, pero pensé que "todo es posible" y "cambio de metáforas" no llegaron al punto, aunque podrían haberse extendido. La sección 'En resumen' de la respuesta de Keelan, aunque algo basada en opiniones, fue un resumen bastante bueno. La respuesta de quen_tin fue precisa pero no tenía una referencia de apoyo. FredBarker tenía una referencia pero no llegó al tema.

Respuestas (3)

No creo que realmente estemos haciendo otra cosa que usar diferentes palabras para lo mismo. Si, por ejemplo, observa la función Haskellmod para el módulo:

mod :: a -> a -> a

Matemáticamente, la función de módulo es algo así como   Z × Z → N   (donde Z es el conjunto de números enteros; N es el conjunto de números naturales, enteros no negativos).

Puedes ver lo mismo en Haskell, excepto que no distinguen entre Z y N, lo cual es matemáticamente correcto, y que usan solo flechas en lugar de × y una flecha.

En matemáticas llamamos a la izquierda de la flecha el dominio ya la derecha el codominio; en programación funcional llamamos a la izquierda las entradas ya la derecha las salidas.

El uso de las palabras 'entrada' y 'salida' en el contexto de un lenguaje de programación funcional es horrible , porque la entrada y la salida cambian y los lenguajes funcionales se basan en la idea de que las cosas no cambian. Cuando está usando entradas y salidas reales (cosas que cambian), está usando el lenguaje de una manera que ya no es estrictamente funcional, con el uso de mónadas . Sin embargo, cuando alguien entiende el concepto de un lenguaje funcional, no creo que usar 'entrada' y 'salida' pueda causar más daño que confusión.

También estás hablando de la diferencia de que la informática lleva tiempo. Los lenguajes funcionales a veces son perezosos , lo que significa que uno solo calculará cosas cuando sea necesario. Por ejemplo, podemos poner el conjunto completo (infinito) de números naturales en una lista, siempre y cuando no le digas que calcule todos los miembros (solicitando la suma o algo así). Este concepto de pereza es, de hecho, muy similar a lo que hacemos en matemáticas. Cuando demostramos algo, rara vez lo calculamos .

El punto de la inferencia física versus la inferencia lógica es un buen punto, especialmente porque es difícil hacer hardware para lenguajes funcionales . Se están realizando investigaciones en la universidad de York, donde están desarrollando el Reduceron , pero hasta donde yo sé, esto aún no está en un nivel en el que podamos ver que la máquina es completamente funcional .

Tal vez, pero no estoy seguro, esto (nivel físico versus nivel lógico) es en realidad la razón por la que hacer el hardware tan difícil: estamos tratando de construir algo que pertenece a un mundo totalmente diferente. ¿Fue Schopenhauer quizás el primer científico informático? :)

No soy completamente consciente de las limitaciones de los lenguajes de programación funcionales, pero puede ser teóricamente posible ordenarle que calcule algo para lo cual necesitará algo infinito (ya sea tiempo o memoria), mientras que las matemáticas pueden hacerlo sin muchos problemas.

En breve:

  • No creo que los lenguajes funcionales traten las funciones de manera muy diferente a como lo hacen las matemáticas, aunque los programadores pueden usar términos confusos.
  • La diferencia que hace el tiempo de operación se puede reducir en gran medida mediante el uso de la ejecución diferida .
  • La causalidad física que trata de imitar la causalidad lógica ciertamente puede causar problemas, pero aún no hemos llegado tan lejos.
No creo que la computación cuántica invierta la flecha del tiempo ni nada, pero me pregunto si podría cambiar la comprensión del tiempo de procesamiento, con operaciones reversibles y demás. En otra nota, recientemente comencé a usar Clojure para secuencias de comandos web, pero me alejé de Haskell. Sin embargo, no puedo evitar preguntarme si extrañaré algo de él.
@dwn una diferencia importante es que Clojure es impuro, 'en el sentido de que no obliga a su programa a ser referencialmente transparente y no se esfuerza por programas 'probables'. La filosofía detrás de Clojure es que la mayoría de las partes de la mayoría de los programas deben ser funcionales' (de clojure.org/function_programming ): cuando el lenguaje no es completamente funcional, se pueden aplicar cosas diferentes. Por lo que sé, Haskell es lo que más se acerca a la plena funcionalidad. Sin embargo, eso también hace que sea un poco difícil de usar si no estás haciendo algo puramente matemático.
@Keelan - Bueno, ¿Idris? coq? Haskell no es realmente el más funcional, solo el más funcional de los lenguajes posiblemente utilizables en el mundo real (ya que tiene bibliotecas, puede manejar la entrada del teclado, etc.).
No es el caso de que los lenguajes funcionales, incluso los lenguajes funcionales puros, sean generalmente perezosos. Haskell es inusual en eso. (También es inusualmente prominente entre los lenguajes funcionales puros).
@RexKerr gracias, mi conocimiento no llega tan lejos.
@ChristianConkle gracias también, no sabía eso.

Respuesta perezosa: Sí, todo es posible

Bien, ahora la respuesta más larga.

Creo que la diferencia de redacción entre "entrada/salida" y "mapeo" se usa debido a los efectos secundarios. Las asignaciones matemáticas no tienen efectos secundarios, son simplemente asignaciones. La diferencia entre tener un valor, 1, y tener una ecuación complicada evaluada en un punto que se asigna a 1 no es importante a menos que desee operar en la ecuación explícitamente.

Los lenguajes de programación funcional intentan evitar los efectos secundarios, para lograr una pureza matemática similar. Sin embargo, existen efectos secundarios que no se pueden evitar, como el consumo de recursos informáticos. Esto obliga a la gente a pensar en términos ligeramente menos matemáticos. Por un lado, cada lenguaje de programación funcional tiene al menos un concepto de procedimiento, "evaluar", que inicia el proceso. Este pequeño núcleo obliga a los programadores a pensar un poco diferente.

Los programadores funcionales tienen un argumento válido: si tengo que evaluar f(1, 2), la respuesta no cambia si evalúo f(1,2) y f(3, 4). Se podría pensar en un lenguaje funcional como todos los valores que coexisten a la vez, en comparación con los lenguajes de procedimiento que tienen efectos secundarios que nos impiden tener la libertad de ejecutar código arbitrario.

En cuanto a que las metáforas se vuelvan más problemáticas, eso depende de lo que consideres problemático. Considere que todas las metáforas de todos los tiempos han sido problemáticas, porque así es como funcionan las metáforas. No hay un campo de estudio en todo el mundo que no tenga un ecosistema de metáforas que surgen cuando son útiles y decaen a medida que se vuelven menos útiles. Espero que este patrón continúe dentro de la informática.

Ya hay grandes ejemplos de lugares donde las metáforas se han derrumbado. Considere, en el mundo de la programación de procedimientos, subprocesos múltiples. Durante mucho tiempo, pudimos usar la máquina de von Neuman como metáfora de nuestra computadora real. Sin embargo, con las operaciones atómicas modernas, nos vemos obligados a admitir la presencia de cachés de memoria y otras cosas que no aparecen en la metáfora. C++ acaba de lanzar una nueva especificación que incluye operaciones atómicas. El 90% del tratamiento atómico de la especificación ahora se trata de cosas que no se pueden explicar usando la máquina de von Neuman. La solución fue que C++ inventó una nueva metáfora: el modelo de memoria C++11, que se acerca más a lo que hace el hardware moderno. Cuando ese modelo falle, inventaremos uno nuevo.

A menudo se dice que una función en matemáticas toma entradas y da salidas. Una función es un concepto más restrictivo que una relación general entre dos dominios: asignará solo un valor en el dominio de salida a cada valor del dominio de entrada (es una relación de muchos a uno). Esta es también una característica definida de las funciones en un lenguaje de programación funcional. Una función matemática no es estrictamente hablando una función de programación, pero en base a estas similitudes, es una abstracción útil para abordar esta última (a diferencia de los lenguajes imperativos donde algunas funciones pueden devolver diferentes valores en diferentes momentos, por ejemplo, cuando usan variables de estado o entradas externas como reloj). En cualquier caso, existen fuertes relaciones entre las matemáticas y la algorítmica. Ambos tienen los mismos fundamentos lógico-matemáticos.

El programador puede esperar una correspondencia directa entre el código y el programa compilado. Cada operación implementada se realizará como tal. Quizás se optimicen, pero el compilador garantiza que el resultado será el mismo. De lo contrario, los programas no serían fiables. En otras palabras, un programador puede razonar de manera confiable "como si" la computadora estuviera leyendo el código en el momento de la ejecución y aplicando funciones matemáticas como lo haría un matemático.

Las optimizaciones en el momento de la compilación dan como resultado una menor confiabilidad en cuanto a las expectativas de duración (solo se garantiza el resultado), pero en la mayoría de los casos, obtener el mismo resultado equivaldrá a realizar las mismas operaciones y una estimación de la duración basada en el código dará un resultado aproximadamente bueno. Creo que la estructura general del programa se refleja generalmente en el programa compilado.

En los lenguajes de programación imperativos existen técnicas para obtener medidas de duración más precisas en tiempo de ejecución, que se utilizan para la creación de perfiles (mejorando la eficiencia del programa). No sé si existen para lenguajes funcionales.