2010-10-22 17 views
13

La libreria FC++ offre un approccio interessante al supporto dei concetti di programmazione funzionale in C++.FC++ è utilizzato da qualsiasi progetto open source?

Un breve esempio dal FAQ:

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

FC++ sembra prendere un sacco di ispirazione da Haskell, nella misura di riutilizzare molti nomi di funzione dal preludio Haskell.

Ho visto un recente article su di esso, ed è stato brevemente menzionato in alcune risposte su StackOverflow, ma non riesco a trovare alcun utilizzo di esso in natura.

Esistono progetti open source che utilizzano attivamente FC++? O qualche storia di progetti che l'hanno usata in passato? O qualcuno ha esperienza personale con esso?

C'è una sezione Clienti sul sito Web, ma l'unico collegamento attivo è a un'altra libreria degli stessi autori (LC++).

Come sfondo: Sto cercando di scrivere plug-in audio a bassa latenza utilizzando le API C++ esistenti e sto cercando strumenti che mi consentano di scrivere codice conciso in uno stile funzionale. Per questo progetto non voglio usare una libreria C++ piuttosto che usare una lingua separata, per evitare di introdurre binding FFI (a causa della complessità) o garbage collection (per mantenere il limite superiore sulla latenza nell'intervallo del secondo millisecondo).

Sono consapevole che le librerie STL e Boost forniscono già il supporto di molti concetti di FP: questo potrebbe essere un approccio più pratico. Sono anche a conoscenza di altri approcci promettenti per la generazione di codice del codice DSP audio da linguaggi funzionali, come il progetto FAUST o Haskell synthesizer package.

risposta

6

Sono il principale sviluppatore originale di FC++, ma non ci lavoro da più di sei anni.Non ho tenuto il passo con C++/boost molto in quel momento, quindi non so come comparare FC++ ora. Il nuovo standard C++ (e le implementazioni come VC++) ha un po 'di cose come lambda e l'inferenza di tipo help che rende parte di ciò che c'è dentro. Tuttavia, ci potrebbero essere ancora dei bit utili, come i tipi di liste pigre e i combinatori di tipo Haskell (e con lo stesso nome). Quindi immagino provarlo e vedere.

(Dato che hai menzionato in tempo reale, dovrei menzionare che le liste usano il conteggio dei riferimenti, quindi se scarti una lunga lista ci può essere un'attesa non banale nel distruttore come tutti i conteggi delle celle andare a zero. Penso che in genere negli scenari di streaming con stream/elenchi infiniti questo è un non-problema, dato che in genere sei solo nello tail nello stream e solo deallocando un nodo alla volta mentre esegui lo streaming.)

+0

Grazie per le informazioni. È davvero utile sapere quale tipo di approccio manterrà bassi i tempi del distruttore, poiché questa è stata la ragione principale per cui ho preso in considerazione il C++. FC++ è un lavoro davvero interessante! – mattbh

8

Questa non è una risposta alla tua domanda corretta, ma la mia esperienza con l'incorporamento di stile funzionale in lingue imperative è stata orribile. Mentre il codice può essere quasi conciso, conserva la complessità del ragionamento che si trova nelle lingue imperative.

La complessità dell'incorporazione di solito richiede la conoscenza più intima dei dettagli e dei casi angolari della lingua. Ciò aumenta notevolmente il costo dell'astrazione, poiché queste cose devono sempre essere prese in attenta considerazione. E con un costo di astrazione così elevato, è più facile semplicemente mettere una funzione effetto collaterale in un generatore di flusso lento e poi morire di bug sottili.

Un esempio dal 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); 
    } 
}; 

Credo che questo sta cercando di esprimere il seguente codice 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 [] 

Vi lascio giudicare la complessità dell'approccio come programma cresce .

Considero la generazione di codice un approccio molto più attraente. Puoi limitarti a un minuscolo sottoinsieme della tua lingua di destinazione, semplificando il porting a una lingua di destinazione diversa. Il costo dell'astrazione in un linguaggio funzionale onesto è quasi zero, poiché, dopo tutto, sono stati progettati per quello (proprio come l'astrazione sul codice imperativo in un linguaggio imperativo è abbastanza economico).

+1

"proprio come l'astrazione sul codice imperativo in un linguaggio imperativo è abbastanza economico" Non sempre; guarda Java. Le caratteristiche di astrazione nei linguaggi funzionali sono ugualmente utili per il codice imperativo. Mancando quelle caratteristiche non è un "paradigma", è solo un difetto di progettazione. – keegan

+0

Grazie, è davvero utile - proverò prima l'approccio del codice gen. Dire una EDSL in Haskell per generare un codice sensibile al tempo di basso livello sarebbe l'ideale. Inoltre ci sono molti progetti open source esistenti per DSP e software embedded in tempo reale che adottano un approccio simile, tra cui FAUST, Feldspar e Haskell Synthesizer e Atom. – mattbh