2010-10-22 24 views
13

La biblioteca FC++ proporciona un enfoque interesante para admitir conceptos de programación funcional en C++.¿Alguno de los proyectos de código abierto usa FC++?

Un breve ejemplo de la FAQ:

take (5, map (odd, enumFrom(1))) 

FC++ parece tomar un montón de inspiración de Haskell, en la medida de la reutilización de muchos nombres de las funciones de la antesala Haskell.

He visto un reciente article al respecto, y se ha mencionado brevemente en algunas respuestas en stackoverflow, pero no puedo encontrar ningún uso de él en la naturaleza.

¿Hay proyectos de código abierto que utilicen activamente FC++? ¿O algún historial de proyectos que lo usaron en el pasado? ¿O alguien tiene experiencia personal con eso?

Hay una sección Clientes en el sitio web, pero el único vínculo activo es para otra biblioteca de los mismos autores (LC++).

Como fondo: Estoy buscando escribir complementos de audio de baja latencia utilizando las API de C++ existentes, y estoy buscando herramientas que me permitan escribir código conciso en un estilo funcional. Para este proyecto, quiero utilizar una biblioteca C++ en lugar de utilizar un lenguaje separado, para evitar la introducción de enlaces FFI (debido a la complejidad) o la recolección de basura (para mantener el límite superior de latencia en el rango de menos de milisegundos).

Soy consciente de que las bibliotecas STL y Boost ya ofrecen soporte de muchos conceptos de PF: este puede ser un enfoque más práctico. También conozco otros enfoques prometedores para la generación de código de código de audio DSP desde lenguajes funcionales, como el proyecto FAUST o el Haskell synthesizer package.

Respuesta

6

Soy el principal desarrollador original de FC++, pero no he trabajado en él en más de seis años.No me he mantenido al día con C++/boost mucho en ese momento, así que no sé cómo se compara FC++ ahora. El nuevo estándar de C++ (y las implementaciones como VC++) tiene un poco de cosas como lambda y la ayuda de inferencia de tipo que hace que algo de lo que está allí sea discutible. Sin embargo, aún puede haber bits útiles, como los tipos de lista diferida y los combinadores similares a Haskell (y con nombres similares). Así que supongo que pruébalo y mira.

(Como mencionó en tiempo real, debo mencionar que las listas usan recuento de referencias, por lo que si 'descarta' una lista larga puede haber una espera no trivial en el destructor como recuentas de todas las celdas Vaya a cero. Creo que normalmente en escenarios de transmisión con infinitas secuencias/listas esto no es un problema, ya que normalmente solo está tail entrando en la transmisión y desasignando cosas solo un nodo a la vez mientras transmite.)

+0

Gracias por la información. Es realmente útil saber qué tipo de enfoque mantendrá los tiempos de destructor bajos, ya que esa fue mi principal razón para considerar C++. ¡FC++ es un trabajo realmente interesante! – mattbh

8

Esta no es una respuesta a su pregunta, pero mi experiencia con la incrustación de estilo funcional en los idiomas imperativos ha sido horrible. Si bien el código puede ser casi tan conciso, conserva la complejidad del razonamiento que se encuentra en los idiomas imperativos.

La complejidad de la incrustación generalmente requiere el conocimiento más íntimo de los detalles y casos de esquina del idioma. Esto aumenta en gran medida el costo de la abstracción, ya que estas cosas siempre deben tenerse en cuenta cuidadosamente. Y con un costo de abstracción tan alto, es más fácil simplemente poner una función de efecto lateral en un generador de flujo diferido y luego morir de errores sutiles.

Un ejemplo de FC++:

struct Insert : public CFunType<int,List<int>,List<int> > { 
    List<int> operator()(int x, const List<int>& l) const { 
     if(null(l) || (x > head(l))) 
     return cons(x, l); 
     else 
     return cons(head(l), curry2(Insert(),x,tail(l))); 
    } 
}; 

struct Isort : public CFunType<List<int>,List<int> > { 
    List<int> operator()(const List<int>& l) const { 
     return foldr(Insert(), List<int>(), l); 
    } 
}; 

Creo que esto está tratando de expresar el siguiente código Haskell:

-- transliterated, and generalized 
insert :: (Ord a) => a -> [a] -> [a] 
insert x [] = [x] 
insert x (a:as) | x > a = x:a:as 
       | otherwise = a:insert x as 

isort :: (Ord a) => [a] -> [a] 
isort = foldr insert [] 

te dejaré para juzgar la complejidad del enfoque como su programa crece .

Considero que la generación de código es un enfoque mucho más atractivo. Puede restringirse a un subconjunto minúsculo de su idioma de destino, lo que facilita el acceso a un idioma de destino diferente. El costo de la abstracción en un lenguaje funcional honesto es casi cero, ya que, después de todo, fueron diseñados para eso (al igual que la abstracción sobre el código imperativo en un lenguaje imperativo es bastante barata).

+1

"del mismo modo que abstraer el código imperativo en un lenguaje imperativo es bastante barato" No siempre; mira a Java. Las características de abstracción en los lenguajes funcionales son igualmente útiles para el código imperativo. La falta de esas características no es un "paradigma", es solo un defecto de diseño. – keegan

+0

Gracias, eso es realmente útil: primero probaré el enfoque code-gen. Tener que decir un EDSL en Haskell para generar un código de bajo nivel de tiempo y tiempo sería ideal. Además, hay muchos proyectos de código abierto para DSP y software embebido en tiempo real que adoptan un enfoque similar, incluidos FAUST, Feldspar y Haskell Synthesizer, y Atom. – mattbh

Cuestiones relacionadas