Programación funcional con MCU(s)

Los lenguajes funcionales como Haskell, LISP o Scheme permiten que un programador trabaje rápidamente utilizando el paradigma de programación funcional . Tienen sus ineficiencias , pero mi aplicación pone más énfasis en la eficiencia del programador que en la eficiencia del programa en sí.

Me gustaría usar la programación funcional en un microcontrolador para controlar la máquina, etc.

¿Qué limitaciones existen, como los recursos mínimos del sistema?
¿Qué implementaciones de ejemplo de estos lenguajes están disponibles?

Si su pregunta es "¿No vale la pena programar cualquier máquina con el lenguaje de programación más poderoso que pueda tener?", se recomienda leer las preguntas de C++ y Java (sobre programación orientada a objetos en lugar de programación funcional).
Su primer párrafo parece argumentativo, lo que le ha valido algunos votos cercanos. Considere cambiar la redacción a algo más pasivo ("Estoy interesado en usar la programación funcional para el control de la máquina, ¿qué ejemplos hay de implementaciones de Haskell/LISP/Scheme para sistemas integrados") o eliminarlo por completo.
No compro tu declaración "ineficiente". Parece exhibir un sesgo extremo hacia el lado del aficionado/prototipo: bajo volumen (también conocido como: 1). C/C++/asm da como resultado un código más pequeño y rápido que se amplifica miles o millones de veces cuando puede usar procesadores con la velocidad y el espacio justos. Incrustado está incrustado. No está programando en un sistema operativo de propósito general.
@sheepsimulator, esta pregunta es muy argumentativa y nunca hay una respuesta clara y correcta. Esto no es para lo que esperan que se use SO.
@Kortuk: hagamos que no sea argumentativo, en lugar de deshacernos de él. Voy a seguir adelante, editarlo y votar por una reapertura, ya hay 2 votos de reapertura y ha recibido respuestas constructivas como la de Joby (que ahora deberá editarse) y la de Pingswept. No tratar de usurpar su ♦ autoridad, solo tratar de ayudar.
@reemrevnivek, hago una llamada sabiendo que se puede reabrir si la comunidad se siente diferente, pero las discusiones sobre lenguajes de programación son inherentemente emocionales.
@Kortuk, reemrvnivek: la razón principal por la que lo pregunté así es porque veo poca discusión sobre el uso de cosas más allá de C/C++ para programar MCU. Encontré útil la respuesta de Joby. Esa fue la única manera que se me ocurrió decirlo; si alguien puede encontrar una manera que parezca menos incendiaria, hágalo.
@sheepsimulator - ¡Listo!
@Kortuk - Por supuesto que lo son. Sin embargo, esto no es (o al menos no debería ser) una discusión sobre los méritos de varios lenguajes de programación. Es (ahora) una pregunta sobre implementaciones de lenguajes de programación funcionales.
@Nick T: "C/C++/asm da como resultado un código más pequeño y rápido que se amplifica miles o millones de veces cuando puede usar procesadores con la velocidad y el espacio suficientes". ¿Qué pasa con el mantenimiento? Un lenguaje funcional con frecuencia puede hacer en una sola línea lo que un programa C requiere 10 para hacer, lo que significa menos espacio para errores. Además, se pueden cumplir (es decir, Haskell) y hacer que se ejecuten en el destino, que es más rápido que los intérpretes. Quería explorar un poco este tema porque un Haskell compilado podría ser igual de rápido, pero más rápido de desarrollar que, por ejemplo, una aplicación C. Quería cuestionar un poco el status quo.
@Sheepsimulator Desafortunadamente, comentarios como el último hacen que las preguntas sean argumentativas.
@Sheepsimulator, puedo comenzar fácilmente a argumentar que el hecho de que sea menos código no significa que haya menos errores. He tenido muchas ocasiones en las que saber menos sobre lo que realmente sucede me hizo crear un error que no tendría si tuviera que escribir más líneas de código.

Respuestas (8)

ARMPIT SCHEME es un intérprete para el lenguaje Scheme (dialecto de Lisp con alcance léxico) que se ejecuta en microcontroladores RISC con núcleo ARM. Se basa en la descripción del Informe revisado sobre el esquema de lenguaje algorítmico (r5rs), con algunas extensiones (para E/S) y algunas omisiones (para caber en la memoria de MCU). Además, está diseñado para soportar multitarea y multiprocesamiento. Se espera que Armpit Scheme se adapte bien a entornos educativos, incluidos proyectos de estudiantes en cursos sobre control e instrumentación, o cursos de diseño final donde se necesitan microcontroladores. Está destinado a enriquecer el espectro de lenguajes interpretados disponibles para MCU (p. ej., BASIC y FORTH) y puede ser una alternativa a los intérpretes de bytecode basados ​​en MCU (p. ej., para Scheme o Java) y a los lenguajes compilados (p. ej., C).

http://armpit.sourceforge.net/

Tu dices:

Usar C, C++, ensamblaje, etc. es bastante ineficiente en comparación con lenguajes como Haskell, LISP o Scheme

El uso de lenguajes de alto nivel es un uso más eficiente del tiempo del programador, pero a menudo puede ser un uso menos eficiente de los recursos informáticos. Para los sistemas integrados fabricados en volumen, el costo y el rendimiento suelen ser una prioridad mayor que el esfuerzo de desarrollo.

También puede programar controladores AVR con Haskell usando Atom/Copilot, por ejemplo http://leepike.wordpress.com/2010/12/18/haskell-and-hardware-for-the-holidays/

Haskell es realmente bueno <3

C, C++ y Assembly están muy cerca del lenguaje de máquina. Al usar un lenguaje de nivel superior, está agregando una sobrecarga adicional a cambio de un desarrollo más rápido/más fácil/etc.

-1: Realmente no estoy de acuerdo con esta respuesta. Aunque tiene razón acerca de que Assembly está cerca del lenguaje de máquina, C y C ++ son lenguajes de alto nivel muy diferentes.
@ BG100, en realidad dibujaría la línea de "nivel alto/nivel bajo" en algún lugar dentro de C en lugar de simplemente llamarlo un lenguaje de alto nivel. Al realizar operaciones aritméticas, de puntero (cadena) y otras tareas básicas comunes, las instrucciones que los compiladores generalmente producen hacen que la CPU manipule directamente los datos sin ninguna capa de abstracción.
@Nick T: Veo su punto, pero considere esto: si escribe una rutina de interrupción que generalmente necesita ejecutarse lo más rápido posible, en C no tendría idea de cuánto tiempo llevaría ejecutarse, pero en ensamblador podría hacerlo. solo cuente las instrucciones. Creo que el nivel bajo es saber EXACTAMENTE lo que está sucediendo en su programa, no lo sabe con certeza si está usando C.
@BG100: la misma instrucción del ensamblador puede tomar diferentes números de ciclos para ejecutarse según los operandos y sus modos de direccionamiento. Aunque en C, una vez que compila, obtiene un código estático que no (no puede) cambiar. Cierto, este es un argumento algo tenue, pero si vamos a discutir las minucias para tratar de trazar una gran línea roja...

He estado programando una placa ARM en Python recientemente y creo que es genial. No es bueno para el control en tiempo real, pero estoy haciendo más cosas relacionadas con la web, lo que es mucho más agradable en un lenguaje de alto nivel que en C.

La mayoría de los microcontroladores siguen siendo dispositivos de 8 y 16 bits (aunque esto está cambiando lentamente). Las dos instancias de lenguajes de nivel superior (Scheme y Python) mencionados en otras respuestas hasta ahora se ejecutan en núcleos ARM de 32 bits. Los dispositivos más pequeños de 8 y 16 bits (que pueden costar solo un par de dólares) no tienen suficiente RAM para admitir los idiomas que se mencionan; por lo general, solo tienen unos pocos KB de RAM.

Además, estos lenguajes de alto nivel no están diseñados para escribir controladores de interrupción de baja latencia y similares. No es inusual que un controlador de interrupciones de microcontrolador sea llamado cientos o miles de veces por segundo, y cada vez se requiera que realice su tarea en decenas de microsegundos o menos.

El esquema se desarrolló a mediados de los años 70 y principios de los 80. De ninguna manera Scheme requiere un procesador de 32 bits o megabytes de memoria. Scheme estaba disponible para PC de clase AT a mediados de los 80. Las implementaciones recientes pueden optimizarse para entornos más ricos en recursos, pero hay ejemplos claros de esquemas que se ejecutan en lo que hoy en día son plataformas informáticas "minúsculas".
@ThePhoton Estoy corregido. Aunque conocía el proyecto BIT, que tiene como objetivo procesadores con decenas de KB de memoria (más de lo que está disponible en la mayoría de los microcontroladores pequeños), acabo de descubrir PICBIT , diseñado por un par de estudiantes de la Université de Montréal y la Université Laval, lo que permite que los programas reales de Scheme se ejecuten en procesadores PIC con tan solo 2K de RAM. Bastante impresionante.

Es posible hacer algo de programación funcional con el lenguaje Lua. Realmente, Lua es un lenguaje multiparadigma; Wikipedia afirma que es un lenguaje 'scripting, imperativo, funcional, orientado a objetos, basado en prototipos'. El lenguaje no impone un solo paradigma, sino que es lo suficientemente flexible como para permitir que el programador implemente cualquier paradigma aplicable a la situación. Ha sido influenciado por Scheme.

Las características de Lua incluyen funciones de primera clase , alcance léxico y cierres y rutinas , que son útiles para la programación funcional. Puede ver cómo se utilizan estas características en la wiki de usuarios de Lua, que tiene una página dedicada a la programación funcional . También encontré este proyecto de Google Code , pero no lo he usado (afirma estar influenciado por Haskell, otro idioma que mencionaste).

eLua es una implementación que está disponible configurada para varias placas de desarrollo para las arquitecturas ARM7TMDI, Cortex-M3, ARM966E-S y AVR32, y es de código abierto para que pueda configurarla para su propia plataforma. Lua está implementado en ANSI C y la fuente completa pesa menos de 200 kB, por lo que debería poder compilarlo para la mayoría de las plataformas con un compilador C. Se recomiendan al menos 128k de Flash y 32k de RAM. Estoy trabajando en un puerto PIC32 para él (aunque todavía en la etapa 'Obtener la placa PIC32') en este momento.

Lo mejor de Lua es que fue diseñado como un lenguaje de unión, por lo que es muy fácil escribir extensiones de C para las cosas que deben ser rápidas (como interrupciones, etc.) y usar las funciones dinámicas e interpretadas del lenguaje para hacer rápido desarrollo en la lógica del programa.

Lua no es un lenguaje puramente funcional, pero puede hacer mucha programación funcional en él, es rápido y pequeño ( en comparación con otros lenguajes de secuencias de comandos ), y no necesita volver a actualizar su dispositivo para probar un programa. ¡Incluso hay un intérprete interactivo!

"¿Hay formas de hacer programación funcional con un lenguaje funcional en una MCU para resolver problemas difíciles?"

Sí, hay maneras. Pero la desventaja es que necesita un procesador de 32 bits, MMU, 128 MB de RAM, SSD, un RTOS y $$$.

Los microcontroladores son diferentes a los microprocesadores. El microcontrolador puede ser solo una CPU de 8 bits, 1K de RAM, 8K de ROM, pero tiene UART, PWM, ADC, etc. incorporados. Y solo cuesta $1.30.

Por lo tanto, podría ejecutar todos esos lenguajes de alto nivel, pero cuesta mucho más hacerlo.

Creo que necesita revisar su definición de microcontrolador. Muchos microcontroladores ahora tienen 128 kB o más de Flash y 64 kB o más de RAM, mucho espacio para ejecutar un intérprete para algunos idiomas pequeños. Parece que está dando especificaciones para un dispositivo Linux integrado; Creo que el OP estaba pidiendo un puerto dedicado.
Si está pagando $ 1.30 por una MCU de 8 bits, entonces hay varias MCU de 32 bits que son más baratas. Además, tenga en cuenta que la mayoría de los MCU de 8 bits en el mercado son arquitecturas terriblemente ineficaces para el código, con diseños heredados de principios de los 80.

Este libro proporciona una forma de programar con una ligera sensación de FP. http://www.state-machine.com/psicc2/

Pero la FP real requiere tener la capacidad de construir funciones en tiempo de ejecución y pasarlas a través de su programa. Aquí tenemos un problema: ¿cómo podemos representar esta función construida? y ¿cómo podemos ejecutar efectivamente esta función? En un sistema grande, podemos usar compilación dinámica que genera código de máquina real en una aplicación de primera función. En MCU solo tenemos RAM para implementar compiladores muy primitivos como el núcleo del lenguaje Forth.

La única forma en que puede usar FP u OOP si lo prefiere es la metaprogramación : escriba programas complejos funcionales/OOP que generen programas para MCU (código fuente C, por ejemplo, o LLVM IL). En esta variante, no está limitado por el paradigma o la complejidad de los métodos de programación.