Notation como herramienta para pensar (1979)
(jsoftware.com)- La notación es una herramienta importante para ayudar al pensamiento y cumple un papel clave tanto en matemáticas como en los lenguajes de programación
- El lenguaje APL fue desarrollado como un intento de combinar las ventajas de la notación matemática con la capacidad de ejecución y la universalidad de un lenguaje de programación
- Las características de una buena notación incluyen concisión, claridad, capacidad de sugerencia, subordinación de los detalles y posibilidad de demostración formal
- Diversas estructuras matemáticas (polinomios, transformaciones, grafos, etc.) pueden expresarse y transformarse eficientemente con APL
- La introducción y el aprendizaje de la notación deben darse de forma natural dentro del contexto, y también son importantes la estructuración y la generalidad de la notación
La notación como herramienta para pensar
- En campos científicos como la química y la botánica, la nomenclatura sistemática también impulsa el desarrollo de la disciplina
- George Boole enfatizó que el lenguaje mismo es un medio para pensar
- La notación matemática es un ejemplo representativo de un lenguaje que apoya el pensamiento, ya que reduce la carga mental y potencia la capacidad de razonar
- A.N. Whitehead y Charles Babbage destacaron la importancia de la notación matemática
El potencial de los lenguajes de programación como herramientas para pensar
- Los lenguajes de programación tienen la fortaleza de la generalidad y la claridad
- Permiten experimentar ideas y realizar experimentos mentales claros mediante la computadora
- Sin embargo, la mayoría de los lenguajes de programación tienen un papel más débil como herramientas para pensar en comparación con la notación matemática
- APL fue diseñado como una notación orientada a apoyar el pensamiento, buscando claridad y precisión
Principales características de una buena notación
- Facilidad para expresar problemas: debe permitir expresar con facilidad estructuras derivadas directamente del problema
- Capacidad de sugerencia: la forma expresada debe insinuar problemas similares o ampliados
- Subordinación de los detalles: debe ofrecer una estructura que simplifique detalles complejos para ayudar al pensamiento
- Concisión: debe permitir una amplia gama de expresiones con un mínimo de símbolos y reglas
- Posibilidad de demostración formal: la notación debe facilitar la prueba formal y el razonamiento deductivo
Introducción a las técnicas básicas de notación en APL
- Usa de manera natural estructuras basadas en arreglos, como vectores y matrices
- Las funciones y operadores se aplican automáticamente elemento por elemento sobre vectores y matrices
- Permite expresar composición de funciones mediante operadores como reducción(
/), escaneo(\) y producto interno(.) - Con símbolos básicos como
⍳,⌽,⍴,+,×,*se pueden construir fórmulas ricas - Todas las funciones siguen la regla de precedencia por la derecha, lo que permite escribir expresiones naturales sin paréntesis
Ejemplos de resolución de problemas y estímulo del pensamiento
- Secuencias matemáticas como los números triangulares y el factorial pueden expresarse con fórmulas simples
- La representación y multiplicación de polinomios, así como operaciones como la derivación, se manejan de forma concisa con reglas consistentes
- La teoría de grafos (árboles, cierre transitivo, árboles de expansión) también puede expresarse claramente con operaciones sobre arreglos
- Puede extenderse a diversos campos, como permutaciones, álgebra booleana y conversión entre sistemas numéricos (factorización prima)
Demostración formal y pensamiento estructurado
- Como todas las operaciones y expresiones se representan de forma claramente ejecutable, es posible validarlas automáticamente con una computadora
- Se presentan diversos ejemplos de demostración formal mediante inducción matemática, búsqueda exhaustiva y enumeración de identidades
- Se demuestran formalmente la partición (identidad) de reducción y escaneo, así como la asociatividad y distributividad del producto interno
- Se prueban directamente las funciones simétricas de Newton y las fórmulas de multiplicación y derivación de polinomios
Comparación entre APL y la notación matemática tradicional
- APL ofrece definición clara de funciones, operaciones sobre arreglos consistentes y un rico sistema de símbolos
- En lugar de reglas de prioridad para cada operación, aplica una regla uniforme de ejecución de derecha a izquierda
- Reduce la complejidad del uso de símbolos matemáticos y apoya la manipulación formal
- Su sintaxis es concisa y sus reglas son consistentes, lo que beneficia tanto a principiantes como a usuarios avanzados
Introducción y aprendizaje de la notación
- Se enfatiza un enfoque en el que la notación necesaria se introduce naturalmente dentro del contexto, sin una "clase de lenguaje" separada
- Los nuevos símbolos se aprenden de forma intuitiva dentro de situaciones problemáticas concretas
- Más que la dificultad de la notación en sí, lo importante es reconocer las distintas posibilidades y la capacidad de expansión que sugiere
Posibilidades de expansión y propuestas para APL
- Se propone ampliar funciones, incluyendo el manejo de números complejos
- Se necesita estandarizar las funciones de elementos únicos (
unique elements) y resumen (summary) - La introducción de operadores más generalizados permitiría dar soporte a temas adicionales, como el cálculo vectorial
- El objetivo es mejorar la claridad del diseño del lenguaje y su capacidad de razonamiento
Equilibrio entre eficiencia y claridad
- Se recomienda definir primero una notación clara y analizable, y luego aumentar la eficiencia mediante optimización
- Clarificar el algoritmo también ayuda posteriormente a la optimización y a la optimización del compilador
- Las expresiones básicas escritas en APL pueden contribuir tanto a la investigación académica como a las aplicaciones industriales
1 comentarios
Comentarios de Hacker News
Es fácil ver la notación como algo parecido a la expansión del shell, es decir, “reemplazar una expresión por otra”, pero en realidad es mucho más profunda.
Un profesor me explicó que los grandes descubrimientos suelen aparecer junto con una nueva notación, y que una nueva notación significa “una nueva forma de pensar este problema”.
Creo que muchos de los problemas sin resolver de hoy también podrían resolverse si apareciera una notación poderosa.
Esto es realmente poderoso, pero se parece más al estilo Lisp; el estilo APL o Clojure va más por hacer que los tipos básicos sean realmente útiles.
En vez de tener 10 estructuras de datos con 10 funciones cada una, se trata de tener 1 estructura de datos con 100 funciones; por eso, en APL, más que crear un DSL, diseñas y acomodas los datos con muchísimo cuidado y luego el resto encaja.
Richard Feynman, cuando era adolescente y aprendía trigonometría, no estaba conforme con la notación de seno y coseno, así que creó sus propios símbolos matemáticos para simplificar las fórmulas y reducir el ruido.
Más adelante también reinventó a la vez la forma de pensar y de expresar la física con cosas como los diagramas de Feynman o la notación slash.
Un ejemplo pequeño: cuando apareció CoffeeScript, la abreviación de lambdas y varias comodidades sintácticas cambiaron mucho la forma de escribir JavaScript, y lo hicieron más fácil de pensar, leer y corregir.
SML/Haskell y la familia Lisp se sienten parecidos.
Creo que también te va a gustar este clip corto de Brian Greene y Barry Mazur: https://youtu.be/8wQepGg8tHA
Históricamente, lo que desplazó a APL no fueron solo los teclados raros, sino también Lotus 1-2-3 de IBM y, poco después, MS Excel.
Ingenieros, académicos, contadores y MBA necesitaban herramientas mejores que la TI-59 o la HP-12C, mientras que el área de ciencias de la computación estaba concentrada en el procesamiento simbólico, la IA y LISP, y al final la industria ocupó ese lugar.
Es una coincidencia desafortunada: APL podría haber tenido una influencia mucho mayor que las hojas de cálculo y haber resuelto muchos más problemas.
La visión original era una notación matemática coherente, ejecutable y escribible a mano, pero nunca llegó a concretarse.
Si te interesa, vale la pena leer este texto: https://mlajtos.mu/posts/new-kind-of-paper
Puedes resolver problemas sin pagar, y el costo aparece cuando distribuyes el resultado compilado frente a clientes de pago.
Si la solución encaja con cierto subconjunto, también puedes moverla a April y ofrecerla desde Common Lisp.
Dicho eso, la gente de APL suele ser muy académica: puede hacer trabajo de ingeniería de forma rápida y concisa, pero si en una empresa de software promedio empiezas a hablar de rangos de funciones o de funtores naperianos, tus colegas podrían sospechar que necesitas ayuda médica.
Una buena parte del desarrollo de software consiste en inventar un lenguaje técnico más o menos formal que exprese cómo hablan y piensan los clientes y usuarios, y en los lenguajes de la familia de Iverson esto no es fácil.
Java durante mucho tiempo obligó a dejar claro qué palabras de negocio entran y salen de cada método, y en ese sentido facilitaba mapear los conceptos de una organización al código.
En APL también se pueden nombrar datos y funciones, pero en cuanto incorporas nombres largos y estructuras de espacios de nombres para mapear una organización externa al código, pierdes concisión y elegancia.
Incluso en los sofisticados sistemas de tipos de la familia ML, a los desarrolladores les cuesta conectar directamente las ontologías cuasilingüísticas inventadas con organizaciones y procesos, y con más frecuencia eligen conceptos matemáticos o académicos.
Es posible si hay alguien capaz de hacer ambas cosas, pero normalmente basta con ser bueno traduciendo hacia el mundo del cliente.
El año pasado, The Array Cast volvió a publicar una entrevista a Iverson de 1982: https://www.arraycast.com/episodes/episode92-iverson
Es bastante interesante y más accesible que la conferencia Turing.
El APL de 1979 no era un lenguaje tan raro y marginal como lo es hoy.
En ese momento los lenguajes de programación todavía no eran fenómenos populares globales como ahora, así que casi todos eran raros y marginales, y C también era bastante nuevo entonces.
Si uno es un poco generoso, APL puede verse como una abstracción no tan lejana de un C denso, que permitía programar la computadora sin implementar directamente manipulación de punteros sobre arreglos.
También hay bastantes libros de texto para aprender matemáticas con la sintaxis de APL [1] o J [2].
Iverson originalmente usó APL como una mejor sintaxis para las matemáticas, y la implementación como lenguaje de programación llegó varios años después.
[1] https://alexalejandre.com/about/#apl
[2] https://code.jsoftware.com/wiki/Books#Math_for_the_Layman
Antes escuchaba un podcast de teoría de tipos que ya fue descontinuado, y era extremadamente críptico.
El concepto básico está conectado con otros conceptos útiles
La hipótesis de Sapir-Whorf también es similar, pero resulta más interesante si se la piensa al revés
En un lenguaje imperfecto hay cosas que no se pueden pensar, o que son difíciles de pensar; entonces cabe preguntarse si hay cosas que no podemos expresar ni pensar con el lenguaje que usamos
Aquí “lenguaje” y “pensamiento” pueden entenderse en un sentido más amplio de lo habitual
Por ejemplo, ¿las reglas de interacción social determinan la forma en que interactuamos? Zeynep Tufekci dice en “Twitter and Teargas” que Twitter hace posibles los flashmobs, pero dificulta el cambio social sostenido
¿Mecanismos sociales como seguir a alguien, comentar o dar like determinan o habilitan la forma en que interactuamos entre nosotros? Otros mecanismos podrían posibilitar un mejor pensamiento colectivo
También está la música. No como notación: ¿la música expresa algo que no se puede expresar bien de otras maneras?
Como alguien que aprendió varios idiomas extranjeros, hay muchas cosas que solo puedo pensar en un idioma específico y que son difíciles de pensar en mi inglés nativo
Por ejemplo, “гулять” en ucraniano y ruso tiene muchos significados que el inglés no capta, así que antes de aprender esos idiomas nunca había pensado en esos sentidos
“Гулять” literalmente significa “caminar”, pero también se usa con el sentido de salir en busca de experiencias, incluidas experiencias sexuales
Uno puede quejarse de que alguien se casó demasiado pronto diciendo “не нагулялся”, es decir, “no caminó lo suficiente”
En inglés hay expresiones parecidas como “sow his wild oats”, pero cuando un solo verbo como “caminar” carga tantos significados, cambia la forma misma de pensar la vida como algo que se recorre caminando
Cuando aprendí árabe también surgieron muchos significados y pensamientos que solo existen en ese idioma; no porque sea imposible explicarlos en inglés, sino porque no hay una notación para expresarlos de forma concisa, así que hace falta un texto largo
A algunas personas les gusta viajar hacia otros pensamientos a través del lenguaje, y otras quedan paralizadas ante esa posibilidad
Como siempre, el éxito está en el equilibrio y en ambos lados
Aunque para un matemático o un científico de la computación sea algo extremadamente obvio, esta idea es muy polémica entre lingüistas y “educadores”
El análogo lingüístico es la hipótesis de Sapir-Whorf, que sostiene que el idioma que uno aprende determina su forma de pensar
Las lenguas naturales son objetos culturales, y mapear culturas, aunque sea en un orden parcial débil, se considera casi un tabú en la academia
También tiene grandes consecuencias en la educación, porque a veces se impide que los estudiantes aprendan la notación que les permitiría razonar de verdad sobre los problemas que enfrentan
Sinceramente, esta parte no la entiendo bien
El hecho de que hablantes de cualquier idioma puedan aprender las mismas matemáticas o los mismos programas de computadora lo demuestra
También es cuestionable que el lenguaje hablado o escrito sea indispensable para pensar
Como mínimo, hay grandes áreas del pensamiento que son posibles sin lenguaje, y los humanos en algún momento no tenían habla, o tenían muy poca; las ideas e intenciones de comunicarse crearon palabras y lenguajes
Por eso se siente extraño ver el idioma aprendido como el modelo básico del pensamiento
Por ejemplo, se llega a afirmar que si una sociedad llama con la misma palabra al color del mar y al color del pasto, entonces no puede experimentar la diferencia entre ambos colores
No sería solo que codifican la experiencia de manera similar en la memoria, sino que no ven la diferencia
Es parecida la afirmación de que, si un idioma no tiene cierto sonido, directamente no puedes oírlo
La discusión sobre notación aquí está más cerca de la idea de que el vocabulario puede usarse para explorar
Es decir, poder decir no solo que oíste algún sonido, sino que escuchaste música y oíste cierta progresión de acordes, etc.
Ahora estoy desarrollando un proyecto en APL
Era algo que llevaba mucho tiempo en el backlog, pero ahora ya estoy escribiendo código de verdad
Pasó bastante tiempo entre el momento en que me interesé y el momento en que pude escribir algo de más de una línea
Al principio de ese proceso descubrí este artículo y lo leí casi absorbiéndolo; ahora esos conceptos se volvieron una base completa para mi pensamiento
De hecho, estoy enseñando NAATOT en un programa de arquitectura
No de arquitectura de software, sino de diseño arquitectónico
Uso una versión editada para conservar el núcleo de Iverson, y dejé solo la matemática y la programación reales necesarias para mostrar el punto y desafiar a los estudiantes a pensar de otra manera las posibilidades de las herramientas de diseño y expresión
Es decir, trata sobre el proceso de formar ideas y la manera de expresarlas ante uno mismo y ante los demás
Si tuviera la oportunidad de hacerlo en un programa más flexible y abierto, me gustaría dictar una clase en la que los estudiantes creen su propio sistema de símbolos y notación para aplicarlo al ámbito del diseño arquitectónico
Lamento no haber terminado la app de notas Freeform que estaba creando antes
Era una app que se compilaba como página web independiente mediante SVG, y creo que era una idea realmente genial para el contenido técnico común en áreas STEM
Un ejemplo antiguo de notas de química está aquí: https://colbyn.github.io/old-school-chem-notes/dev/chemistry-1010---fall-2021/week-14-acids-and-bases.html
Me pregunto qué sistema usará ahora
Durante años vi APL como una especie de magia, hasta que a principios de este año me tomé el tiempo de aprenderlo.
Me sorprendió que con APL se pueda meter una cantidad enorme de código, tanta como para caber en un solo tuit.
Es divertido, pero fue difícil de usar.
Después de escribirlo, casi siempre pienso: “¿De verdad tardé tanto en escribir esto?”, y me pregunto si debería haber usado otra herramienta.
Pero, en realidad, no resulta intuitivo que otra herramienta probablemente habría tomado mucho más tiempo.
La parte que se siente difícil y consume tiempo es, en realidad, el proceso de verse obligado a ordenar la especificación del problema de una forma más condensada.
Es parecido a subir por un camino más empinado pero mucho más corto: se siente más pesado, pero en realidad es menos trabajo.
Por eso siento que debería aprender y usar APL.
Personalmente no estoy de acuerdo con la premisa del artículo de que “la notación matemática carece de universalidad y debe interpretarse de forma distinta según el tema, el autor y el contexto”.
Creo que una notación separada de la visualización del problema y de la ergonomía tiene un costo alto.
Algunos académicos prefieren notaciones que oculten mucha complejidad para generar revelaciones tipo “eureka” o equivalencias inesperadas, pero en algunos casos eso más bien puede volver las cosas confusas y propensas a errores.
Aun así, es cierto que es una herramienta importante para comunicar el proceso de pensamiento.
Creo que tener una sola notación estándar para un área o áreas cercanas reprime bastante los aspectos creativos, artísticos y exploratorios del razonamiento y la resolución de problemas.
También hay una excelente explicación de Terry Tao sobre notación: https://news.ycombinator.com/item?id=23911903
En matemáticas hay esfuerzos por crear sistemas de razonamiento “empresariales” como Lean y Coq, y en esos casos un sistema de notación universal tiene sentido.
Pero para la exploración personal, puede ser mejor encajar cualquier cosa que funcione.
Personalmente, esto me resultó más difícil en la educación.
En clases de álgebra y similares, me costaba cuando el profesor no trataba de forma consistente o sincera sus decisiones y preferencias personales sobre notación, y mis habilidades matemáticas mejoraron mucho al estudiar teoría de tipos y teoría de demostración mecánica.
Creo que el concepto de “subordinación de los detalles” del artículo no se exploró con suficiente profundidad.
Después de leer y escribir aplicaciones en APL durante mucho tiempo, me di cuenta de que este concepto apunta a una forma de gestionar la complejidad fundamentalmente distinta de la abstracción.
Estamos rodeados de barreras de abstracción como API, bibliotecas, módulos, paquetes e interfaces, y el resultado son problemas conocidos como altas torres de abstracción, desarrolladores que pegan API, desconexión del hardware y dificultad para razonar sobre el rendimiento.
APL facilita mucho otro enfoque.
En vez de diseñar abstracciones, uno diseña cuidadosamente los datos para que puedan manipularse con facilidad mediante expresiones simples.
Es decir, se usan operaciones primitivas directamente donde normalmente habría funciones de biblioteca o términos de un DSL.
Por ejemplo, con una tabla de cadenas, un arreglo de claves y un arreglo de valores, se puede crear una estructura parecida a un hashmap con valores vectoriales y claves internadas, y manejar inserciones, salidas y eliminaciones directamente con expresiones de APL.
Lo bueno de este enfoque es que cada expresión no es una caja negra, por lo que puede ajustarse de forma natural a una necesidad específica.
En una inserción normal en un hashmap habría que tener código para agregar una clave nueva, pero aquí se aprovecha el invariante común de que solo se agregan valores a claves existentes.
Con una API de biblioteca, habría hecho falta tener rutas de código que no se usan, varias variantes de funciones de inserción, o una inferencia de tipos sofisticada para eliminar código muerto.
Ese enfoque hace que preocupaciones ajenas al dominio se filtren en la base de código.
Si en vez de ocultar los detalles se los subordina, se puede acceder a los detalles específicos del dominio tanto como haga falta, y los detalles irrelevantes pueden quedarse discretamente en segundo plano hasta que se los necesite.
Por supuesto, hay que estar muy familiarizado con las expresiones de APL, pero no creo que sea una carga mucho mayor que aprender a fondo algo como el ecosistema de Python.
En la práctica, los símbolos de APL desaparecen en el fondo y empiezan a verse como frases con significado, igual que uno lee palabras y frases en inglés, no letra por letra.
En la mayoría de los lenguajes es imposible, pero si el lenguaje es lo bastante conciso y expresivo, vuelve a ser posible en un rango bastante amplio.
Siempre me viene a la mente la idea de que Arthur Whitney detesta de verdad hacer scroll.
Tampoco hace falta tener 20 archivos abiertos y andar siguiendo “ir a la definición”.
Cuando todo el programa cabe en una página, eso desaparece, y se navega con el movimiento de los ojos.
Siento sinceramente que debería dedicar tiempo a aprenderlo.
También conecta profundamente con las dificultades que he vivido en las últimas semanas.
Estoy viendo código Python legacy demasiado fuertemente acoplado, y todos los intentos previos de “mejora” consistieron en apilar más abstracciones sobre un modelo de datos equivocado.
Al leer el código linealmente, no se puede saber qué métodos modifican el objeto de entrada.
Algunos lo modifican y otros no; a veces incluso devuelven sin cambios el mismo argumento de entrada.
Antes que un mar de rodeos donde una factory devuelve varios calculadores que ni siquiera comparten la misma interfaz, preferiría cadenas mágicas que al menos pueda analizar y entender.
Porque todas las operaciones son O(n).
Se pueden usar operadores generales, pero hay que entender con cuidado qué significan los pares de valores dentro de la lógica del dominio y cómo mantener la estructura correcta en cada operación.
Quien lea el programa por primera vez tendrá la misma dificultad para entender el significado del dominio de negocio, no las operaciones primitivas.
Si hay una mejora, creo que no es porque la complejidad esté en otro lugar, sino porque el código y los valores reales se ven al mismo tiempo.
Lo que hace más fácil la programación compleja es tener los datos en tiempo de ejecución y las operaciones del código uno al lado del otro; por eso las herramientas de IDE siguen mejorando depuradores e inspectores para mostrar qué hace el programa en cada paso.
En este contexto, abstraer parte de las operaciones o abstraer parte de la estructura de datos no cambia que crear una abstracción nueva, buena y concisa siga siendo algo positivo.
El código de inserción del ejemplo no es, en su mayor parte, la operación de agregado deseada, sino limpieza de datos para transformar la forma que permite ingresar el intérprete en la forma necesaria.
⍪←es el agregado real, y↓⍉↑()()()se parece más a parseo y transformación de entrada para esquivar las limitaciones de APL y del parser de entrada del intérprete.El código de eliminación también tiene que crear arreglos booleanos ajenos al dominio del problema, por ejemplo envolviendo
'buggy'para buscarlo como un único elemento de un arreglo anidado.Decir “crear un hashmap de valores vectoriales” también induce a error, porque no hay hashing real.
No hay verificación de claves duplicadas, no se puede elegir el hash ni ajustar velocidad y distribución, y las claves se agregan en orden, por lo que la búsqueda también se vuelve lenta.
Dyalog APL también tiene I-Beam 1500, un comando mágico del intérprete que marca arreglos como objetivos de hashing interno para búsquedas rápidas, pero hay que recordar constantemente que la abstracción interna se filtra.
A APL le faltan buenas ideas de diseño de lenguajes y herramientas como “el pozo del éxito”, “solo debe haber una forma”, “la primera forma que se te ocurra debería ser la correcta” y “las tareas distintas deberían verse distintas”.
En Python o C#, una sintaxis como
kv={'a':1, 'b':2}simplemente funciona, y si olvidas una llave o dos puntos se ve claramente mal, mientras el editor y el compilador ayudan.Las implementaciones de APL dependen de funciones mágicas del intérprete como
⎕NGET,⎕CSVy⎕JSONpara entrada y salida, y también son débiles en manejo de errores, logging y depuración.La expresión completa se ejecuta como una sola unidad, y por los hooks y forks tampoco es fácil dividirla.
Al final, para poder experimentar y aprender, hay que tener una intuición precisa de las distintas formas de arreglos, de por qué
⊂3parece no hacer nada, de la diferencia entre⊆y⊂, de la extensión escalar, etc.Incluso un patrón de acceso inmediato como “si la clave existe, actualizar; si no, agregar” en APL obliga a replantearse desde la forma de ramificar.
En Python se resolvería con
if/elseykey in map, y en C# conif/elseymap.Contains(key), pero en APL uno termina pensando en cómo reimplementar funcionalidad básica.Es parecido a lo que argumentó Aaron Hsu, pero se siente como Up-Goer 5 o Toki Pona, donde no puedes decir “camión de bomberos” y tienes que decir “el auto de las personas que hacen el trabajo de detener el fuego”.
[1] https://docs.dyalog.com/latest/CheatSheet%20-%20I-Beams.pdf
[3] https://aplwiki.com/wiki/Scalar_extension
[4] https://xkcd.com/1133/