Programming Languages From Hell Proseminar im Sommersemester 2010 FC++ Bernhard Waltl Technische Universität München 7.6.2010 Zusammenfassung Bei FC++[2] handelt es sich um eine Bibliothek (erstellt von Brian McNamara und Yannis Smaragdakis), die es ermöglicht, in C++ funktional zu programmieren. Durch FC++ ist es möglich, mit Funktionen höherer Ordnung zu arbeiten. Polymorphe Funktionen werden ebenfalls unterstützt. Um diese funktionalen Features umzusetzen bedient sich FC++ der Typinferenz von C++. Damit stellt es eine gute Erweiterung zu dem bereits vorhandenen Objekt Modell von C++ dar. Weiters bietet die Bibliothek viele nützliche Funktionen und Klassen, unter anderem eine “lazy list” Klasse, die die Erstellung von unendlichen Datenstrukturen ermöglicht. Auch das “currying” - Konzept kann auf vorhandene C++ - Funktionen angewandt werden. 1 Einleitung Teile der C++ Standard Library wurden in funktionalem Stil programmiert. Obwohl die C++ Standard Library in geringem Maße Funktionen höherer Ordnung und “currying” unterstützt, stellt es keine funktionalen Aspekte für den anwendungsorientierten Programmierer zur Verfügung. Die C++ Standard Library besitzt zwei Nachteile: • Hohe Komplexität bei polymorphen Funktionen: Polymorphe Funktionen müssen zuerst monomorph instanziert werden. Dabei kann die Implementierung zum Teil sehr komplex werden. • Um polymorphe Funktionen in C++ zu realisieren, kann man Function Templates benutzen.[1] Function Templates können nicht als Argumente von anderen Function Templates verwendet werden. Das heißt polymorphe Funktionen, die über Function Templates realisiert wurden, können keine anderen polymorphen Funktionen als Argumente über einen Funktionsaufruf bekommen. 1 Genau diese Lücken versucht FC++ zu schließen. Bei dieser Bibliothek handelt es sich um eine C++ Bibliothek, die sich ausschließlich der in C++ verfügbaren Sprachkonstrukte bedient und voll kompatibel zu den vorhandenen Compilern und der Laufzeitumgebung ist. Bei der Umsetzung der Bibliothek wurde die C++ - Typinferenz genutzt. Bei der Typinferenz handelt es sich um einen Prozess, der die aufzurufende Funktion anhand der Typen der Argumente bestimmt. Moderne funktionale Programmiersprachen wie Haskell und ML verfügen über eine automatische Typinferenz. Bei C++ ist dieser Bestimmungsprozess halbautomatisch, das heißt, dass die aufzurufende Funktion nur mit Hilfe der übergebenen Argumenttypen bestimmt werden kann. Der Datentyp des Rückgabewertes einer Funktion reicht nicht aus, um die Bestimmung eindeutig durchzuführen, da dieser nicht notwendigerweise verwendet werden muss. Mit Hilfe der FC++ Bibliothek erhält man Möglichkeiten, mit polymorphen Funktionen höherer Ordnung zu arbeiten, als seien sie elementare Datentypen von C++ wie zum Beispiel Integer oder Pointer. 2 Konzepte von FC++ In diesem Kapitel werden die wesentlichen Konzepte von FC++ behandelt. 2.1 Functoide Der Ausdruck Functoid wurde von Konstantin Läufer geprägt, der 1994 Versuche unternommen hat, ein Framework zu entwickeln, das Funktionen höherer Ordnung in C++ besser unterstützt [3]. Konkret handelt es sich dabei um die Implementierung von funktionalen Methoden in FC++. Der Begriff der funktionalen Methode soll verdeutlichen, dass die Funktion nicht mehr im klassischen prozeduralen Kontext zu sehen, ist sondern im Sinne FC++, das heißt funktional. C++ ist eine objekt-orientierte klassenbasierte Programmiersprache. Zum Definieren von Klassen verwendet man entweder das Schlüsselwort struct oder class. C++ bietet eine Möglichkeit den call-Operator zu überladen. Dies ermöglicht es, Objekte zu erstellen, welche sich von der Lesbarkeit und vom Verhalten nicht von normalen Funktionen unterscheiden lassen. Das folgende Beispiel soll dies verdeutlichen: struct I n c { int operator ( ) ( int v a l u e ) { return v a l u e +1; } } inc ; i n c ( 1 4 6 ) ; // −−> E r g e b n i s : 147 Das Problem bei Objekten dieser Art ist, dass das Objekt selbst einen Datentyp darstellt und der Rückgabewert des Objekts vom Typ Inc ist. Die Signatur 2 des Objekts ist int → int. Dies kann der Compiler aber nicht erkennen, weil die Sprache dieses Konzept nicht vorsieht. Das Wissen um die Signatur eines Objekts ist jedoch entscheidend für weitere Konzepte (zB. Polymorphismus). FC++ versucht diese Probleme zu lösen und umzusetzen. 2.1.1 direkt monomorphe Functoide Die einfachste Art der Functoide stellen die direkt monomorphen Functoide dar.[6] Das oben definierte Objekt Inc sieht als direct Functoid wie folgt aus: struct I n c : public CFunType<int , int> { int operator ( ) ( int v a l u e ) { return v a l u e +1; } } inc ; Die Idee hinter den Functoiden ist folgende: man versucht die Typdefinition in dem Objekt selbst zu hinterlegen. Deshalb erweitert man den Functoid um die Funktion Sig, welche die Signatur des zugrundeliegenden Objekts darstellt. Diese Funktion wird jedoch bei dieser Art von Functoiden nicht vom Programmierer selbst definiert, sondern von einer in der Bibliothek implementierten Klasse geerbt. In unserem einfachen Beispiel ist dies die Klasse CFunType. Es handelt sich dabei um ein Template, dessen einzige Aufgabe darin besteht, die Signaturfunktion zu vererben. Im Kern handelt es sich um eine Funktion, die zum Zeitpunkt des Kompilierens benötigt wird und für jede Instanz des Objekts immer dasselbe Ergebnis zurückliefert. Die Signatur des Functoids muss zwingendermaßen redundant angegeben werden: • bei der Definition der Funktion, die den () - Operator überlädt • bei der Spezifikation der Basisklasse (CFunTypehint, inti) 2.1.2 direkt polymorphe Functoide Direkt polymorphe Functoide unterstützen Polymorphismus, ein wesentlicher Bestandteil der Programmiersprache C++.[6, 5] Die Funktionsweise wird an Hand eines Beispiels erläutert. Die Funktion tail liefert den Rest einer Liste, unabhängig vom konkreten Datentyp der Listenelemente, mit der Signatur: [α] → [α]. Eine Implementierung der Funktion in C++ könnte folgendermaßen aussehen: struct T a i l { template <c l a s s T> L i s t <T> operator ( ) ( L i s t <T>& l ) { return l . t a i l ( ) ; } } tail ; 3 Wegen der C++ - Typinferenz ist es erforderlich, dass für jeden Datentyp, der auf die Funktion tail zugreift, konkrete Instanzen angelegt werden. Das Template kann sowohl auf eine Liste von Integervariablen als auch auf eine Liste von Strings angewendet werden. C++ wertet den beim Aufruf zugrundeliegenden Datentyp aus und wendet die entsprechende Funktion an. Die Struktur definiert einen neuen Datentyp Tail die Signatur des () - Operators ListhTi → ListhTi ist nicht in diesem Datentyp enthalten. Das hat dasselbe Problem zur Folge, dass man auch schon bei monomorphen Functoiden hatte. Die Lösung ist wie bei den monomorphen Functoiden eine Memberfunktion Sig zu definieren, welche die Signatur des polymorphen Funtoiden repräsentiert. Die Implementierung hat folgende Form: struct T a i l { template <c l a s s L> struct S i g : public FunType<L , L> { } ; template <c l a s s T> L i s t <T> operator ( ) ( L i s t <T>& l ) { return l . t a i l ( ) ; } } listTail ; Die Bezeichnungen der Datentypen in der Memberfunktion Sig muss nicht notwendigerweise mit den Bezeichnungen des überladenen () - Operators übereinstimmen. Zu beachten ist, dass die Anzahl der Parameter stimmt, das bedeutet in diesem Fall, dass die Funktion mit einem Argument vom Typ L aufgerufen wird und einen Parameter vom selben Typ zurückliefert. Generell gilt, dass ein direkter Funktoid aus einer Klasse/Struktur mit dem () - Operator und einer Memberfunktion Sig besteht. Polymorphe Functoide können sehr einfach in monomorphe konvertiert werden. Die FC++ - Bibliothek bietet mit der Funktion monomorphizeN eine Möglichkeit dies durchzuführen. Beispielsweise liefert ein Aufruf von L i s t <int> l = l i s t w i t h ( 1 , 2 , 3 , 4 ) ; Fun1<L i s t <int >, L i s t <int> > monoTail = monomorphize1<L i s t <int >, L i s t <int> >( T a i l ( ) ) ; L i s t <int> newL = monoTail ( l ) ; a s s e r t ( newL == l i s t w i t h ( 2 , 3 , 4 ) ) ; einen monomorphen Functoid der mit Integer - Listen arbeiten kann. Bei direkten Functoiden ergeben sich trotzdem noch Probleme dadurch, dass es sich nicht um first-class Entitäten handelt. Ein Objekt wird als “first-class Entity” bezeichnet wenn es • in Variablen oder Datenstrukturen gespeichert werden kann. • als Argumente an Funktionen übergeben werden kann. • das Ergebnis einer Funktion sein kann (Rückgabewert). • zur Laufzeit erzeugt werden kann. 4 2.1.3 indirekte Functoide Es nicht möglich, eine Laufzeitvariable zu definieren, die mehrere verschiedene Functoide mit derselben Signatur zugewiesen bekommt. Das resultiert aus dem Problem mit dem Gebrauch von Klassen/Strukturen zur Functoidimplementierung. struct Dec : public CFunType<int , int> { int operator ( ) ( int v a l u e ) { return val ue −1; } }; I n c myInc ; // S i g n a t u r : i n t −> i n t Dec myDec ; // S i g n a t u r : i n t −> i n t int a = 1 ; myInc ( a ) ; //−−> E r g e b n i s : a = 2 myDec ( a ) ; //−−> E r g e b n i s : a = 1 myInc = myDec ; // Kann NICHT f u n k t i o n i e r n ! // b e i d e F u n c t o i d e b e s i t z e n d i e s e l b e S i g n a t u r // a b e r u n t e r s c h i e d l i c h e Datentypen Eine Möglichkeit dies zu umgehen, besteht darin, Functoide mit derselben Signatur in einer Art Klassenhierachie zusammenzufassen. In der Basisklasse wird der () - Operator als virtual definiert um sicherzustellen, dass bei der Verwendung die richtige Funktion aufgerufen wird. Polymorphismus ist jedoch nur möglich, wenn man auf die Funktion indirekt, das heißt mithilfe von Zeigern zugreift. Die FC++ - Bibliothek liefert uns zu diesem Sachverhalt bereits eine fertig implementierte Lösung: indirekte Functoide. Die Bibliothek kümmert sich intern um die Referenzen auf Funktionen. Man kann mit Funktionsobjekten arbeiten wie mit Variablen. Die interne Implementierung der indirekten Functoide ist wie folgt: template <c l a s s Arg1 , c l a s s R e s u l t > c l a s s Fun1 : public CFunType<Arg1 , R e s u l t > { Ref<Fun1Impl<Arg1 , R e s u l t > > r e f ; ... public : typedef Fun1Impl<Arg1 , R e s u l t >∗ Impl ; Fun1 ( Impl i ) : r e f ( i ) {} R e s u l t operator ( ) ( const Arg1& x ) const { return r e f −>operator ( ) ( x ) ; } ... }; template <c l a s s Arg1 , c l a s s R e s u l t > struct Fun1Impl 5 : public CFunType<Arg1 , R e s u l t > { v i r t u a l R e s u l t operator ( ) ( const Arg1 ) const = 0 ; v i r t u a l ˜ Fun1Impl ( ) { } ; }; Die Klasse Fun1 stellt die Wrapperklasse für alle Functoide dar, die einen einzigen Parameter als Argument übernehmen und einen Rückgabewert haben. Sie wird von der Klasse CFunTypehArg1, Resulti abgeleitet. Intern besitzt Fun1 eine Instanz von Ref, die sich um die Verwaltung der Referenzen kümmert. Der () - Operator ruft die Implementierung des davon abgeleiteten Objekts auf. Man beachte, dass dieser Aufruf indirekt, das heißt mit Zeigern, realisiert wird und somit erst die eigentliche Polymorphie ermöglicht. Dieser Aufruf geschieht jedoch gekapselt und ist für den Anwender nicht sichtbar. Monomorphe Funktionen können leicht in indirekte Funktionen konvertiert werden. Dazu stellt uns die FC++ - Bibliothek die Funktion makeFunN zur Verfügung. Fun1<int , int> f = makeFun1 ( I n c ) ; f ( 1 4 6 ) ; // −−> E r g e b n i s : 147 f = makeFun ( Dec ) f ( 1 4 6 ) ; // −−> E r g e b n i s : 145 Genau genommen kann auf den Aufruf von makeFun1() sogar verzichtet werden, da es über die Sig - Funktion bereits möglich ist, die Funktionen automatisch zuzuweisen. Diese Art der Functoide hat den Vorteil gegenüber herkömmlichen Funktionen von C++, dass sie als Parameter übergeben werden und Ergebnisse in Form von Rückgabewerten sein können. Bestehende C++ Funktionen können mit dem Operator ptr to fun aus der FC++ Bibliothek in indirekte Functoide konvertiert werden. [5] Das folgende Beispiel verdeutlicht die Funktionsweise der ptr to fun - Funktion: int twoTimes ( int v a l u e ) { return 2∗ v a l u e ; } bool sameNumber ( int val ue , char∗ s t r V a l ) { return ( v a l u e==a t o i ( s t r V a l ) ) ; } Fun1<int , int> myDouble = p t r t o f u n (&twoTimes ) ; myDouble ( 1 0 2 4 ) ; // −−> E r g e b n i s : 2048 Fun2<int , char ∗ , bool> myNumberCheck = p t r t o f u n (&sameNumber ) ; myNumberCheck ( myDouble ( 1 0 2 4 ) , ” 2048 ” ) ; // −−> E r g e b n i s : t r u e myNumberCheck ( 1 0 2 4 , 1 0 2 4 ) ; 6 // // // // Compiler F e h l e r : ‘ R e s u l t f c p p : : Fun2<Arg1 , Arg2 , R e s u l t > : : o p e r a t o r ( ) ( c o n s t Arg1&, c o n s t Arg2&) c o n s t [ w i t h Arg1 = i n t , Arg2 = cha r ∗ , R e s u l t = b o o l ] ’ Die Funktion twoTimes ist eine C++ - Funktion, die als Parameter einen Wert vom Typ int nimmt und einen Wert vom selben Typ (int) zurückliefert. Wendet man die ptr to fun - Funktion darauf an, so erhält man einen indirekten Functoid, der in einer Variable myDouble gespeichert wird. Bei der Variable myDouble handelt es sich um eine sogenannte first-class Entität. Grundsätzlich gilt, dass alle Ergebnisse von der ptr to fun - Funktion “first-class Entities” sind. Die Variable myDouble ist vom Typ Fun1hint, inti. Anhand dieser Notation lässt sich ablesen, dass die Funktion einen Wert vom Typ int nimmt und einen Wert von Typ int zurückliefert. Diese Notation wird in der gesamten FC++ Bibliothek beibehalten. Das letzte Argument in der Liste stellt immer den Typ des Rückgabewertes dar und die Werte von der ersten bis zur vorletzten Stelle entsprechen den Parametertypen. Die C++ - Funktion sameNumber vergleicht zwei übergebene Parameter ob sie die gleiche Zahl darstellen. Der Aufruf von ptr to fun liefert nun einen Wert vom Typ Fun1hint, char*, booli zurück. Diese Notation entspricht folgender Signatur: int → char* → bool. Sie nimmt also zwei verschiedene Parametertypen entgegen, zuerst einen Wert vom Typ int und einen zweiten Wert vom Typ char*. Besonders deutlich ist dies nochmal an der Fehlermeldung des Compilers zu sehen, wenn man versucht, den Functoid mit ungeeigneten Parameter aufzurufen. Der () - Operator des Functoids erwartet ein Arg1 vom Typ int, ein Arg2 vom Typ char* und liefert als Result einen Wert vom Typ bool. Bei vielen der von FC++ zu Verfügung gestellten Funktionen und implementierten Objekten ist die Anzahl der Argumente N bereits im Funktionsnamen enthalten (z.B. FunN, makeFunN, CurryN). Das hat zur Folge, dass die Anzahl der Argumente, die ein Functoid unterstützt, immer beschränkt ist. 2.2 Lazy Lists In FC++ gibt es die Möglichkeit, sogenannte “lazy lists” zu verwenden [6]. Dabei handelt es sich um eine Reihe von Werten und einer Funktion (thunk ). Die Idee besteht nun darin, die einzelnen Elemente “lazy” zu bestimmen, das heißt wenn man das Element auch tatsächlich benötigt. Anstatt die Funktion bei jedem Zugriff auf das gleiche Element ausführen zu müssen, wird das Ergebnis aus dem ersten Aufruf gespeichert. Dieses caching bringt erhebliche Perfomancesteigerungen. Mit diesen Listen ist es möglich unendliche Datenstrukturen zu erstellen. Der Aufruf von enumFrom(N) liefert eine Liste von Zahlen zurück, beginnend bei N. int x=1, y=2, z =3; s t r i n g s=” S o k r a t e s ” , t=” P la to n ” , u=” A r i s t o t e l e s ” ; 7 L i s t <int> l 1 = c o n s ( x , c o n s ( y , c o n s ( z , NIL ) ) ) ; L i s t <s t r i n g > l 2 = c o n s ( s , c o n s ( t , c o n s ( u , NIL ) ) ) ; L i s t <int> l 3 = a s s e r t ( take (5 , L i s t <int> l 4 = a s s e r t ( take (5 , 2.2.1 enumFrom ( 1 ) ; l 3 ) == l i s t w i t h ( 1 , 2 , 3 , 4 , 5 ) ) ; map( twoTimes , l 3 ) ; l 4 ) == l i s t w i t h ( 2 , 4 , 6 , 8 , 1 0 ) ) ; Struktur der “lazy list” Bei der Implementierung der Datenstruktur der lazy list hat man mehrere Möglichkeiten, wie die Werte und die Funktion, die darauf angewendet wird, abspeichert werden. Es geht dabei um die Frage wie die Liste aufgebaut und welcher Teil der Daten in den einzelnen Elementen gespeichert wird. Die effizienteste Implementierung ist die sogenannte MIDDLE - Version. [6] Die MIDDLE - Version setzt das Problem folgendermaßen um: Jedes Listenelement ist intern als Tupel und Funktion realisiert. Die Funktion ermittelt den Wert des Elements und das Tupel dient als Container für den Wert und beinhaltet auch die Adresse des nächsten Listenelements. Abbildung 1: Schematische Darstellung der MIDDLE - Version Ein Realisierung der Liste könnte in C++ so aussehen: class List { Cache ∗ c ; }; c l a s s Cache { typedef p a i r <int , L i s t > Value ; Fun0<Value> f u n c t i o n ; Value v a l u e ; }; 2.3 Lambda Ausdrücke in FC++ Mit FC++ ist es möglich, anonyme Funktionen, sogenannte Lambda Ausdrücke, zur Laufzeit zu generieren und zu verwenden. [7] Dazu folgendes Beispiel: 8 LambdaVar<1> X; LambdaVar<2> Y; lambda (X,Y ) [ p l u s [ m u l t i p l i e s [ 3 ,X] , Y ] ] ( 3 , 1 ) ; //−−> E r g e b n i s : 10 Aus diesem Codebeispiel kann man drei wesentliche Eigenschaften ableiten, die die FC++ Bibliothek fordert: • Variablen in Lambdaausdrücken LambdaVar müssen außerhalb definiert werden. Es gibt keine Einschränkungen bezüglich der Anzahl der verwendeten Lambdavariablen, diese müssen jedoch mit eindeutigen Integerwerten definiert werden. • Das Gründgerüst für jeden Ausdruck sieht folgendermaßen aus: lambda(lambdaVariablen)[lambdaAusdruck] • Functoide innerhalb von Lambdaausdrücken werden mit dem [ ]-Operator anstatt des ()-Operators aufgerufen. Ein Problem, das die Sprache C++ bedingt, ist die strikte Auswertung des Ausdrucks. C++ wertet einen Ausdruck aus, sobald alle dafür erforderlichen Argumente bekannt sind. Diese Einschränkung wird in FC++ umgangen, indem man eine eigene Syntax dafür einführt: Functoidaufrufe mit dem [ ]-Operator. Der Aufruf von multiplies wäre nicht mit dem ()-Operator durchführbar. Das würde zu einem Fehler zum Übersetzungszeitpunkt führen. Wird der Functoid mit dem [ ]-Operator aufgerufen so kümmert sich FC++ um die verzögerte Ausführung und wertet den Ausdruck erst aus, sobald er benötigt wird. In Lambdaausdrücken ist es möglich, if-then-else Zweige zu definieren. In FC++ existieren drei verschiedene if-Konstrukte: i f 0 [ boolLambdaAusdruck , trueLambdaAusdruck , falseLambdaAusdruck ] i f 1 [ boolLambdaAusdruck , trueLambdaAusdruck , falseLambdaAusdruck ] i f 2 [ boolLambdaAusdruck , trueLambdaAusdruck , falseLambdaAusdruck ] Die drei Versionen der if-Anweisung unterscheiden sich in der Art in der sie den Rückgabetyp bestimmen, während if0 sicherstellt, dass der true und der false - Zweig denselben Datentyp liefern, so entscheidet if1 bzw. if2 nur anhand des true oder false - Zweigs. Deutlich wird der Unterschied an einem Beispiel: bool e q u a l s ( int a , int b ) { return ( a==b ) ; } LambdaVar<3> F ; lambda (X ) [ l e t r e c [ F == lambda (Y ) [ i f 1 [ Y %( p t r t o f u n (& e q u a l s ))% 0 , 1, Y %m u l t i p l i e s% F [Y %minus% 1 ] ] ] ] . i n [ F [X] ] ] ( 5 ) //−−> E r g e b n i s : 120 9 Dieses Codebeispiel verwendet die Möglichkeiten aus dem Bereich der Lambdaausdrücke, um zur Laufzeit eine Funktion zu definieren, die die Fakultät einer Zahl berechnet. Das Schlüsselwort letrec definiert in dem Ausdruck eine Variable F, die in dem zugehörigen in[ ] Bereich aufgerufen werden kann. Die Variable F muss rekursiv verwendbar sein, sonst wäre es nicht möglich, diese im false-Zweig der if-Anweisung zu verwenden. Die % Zeichen ermöglichen es, die Funktionen mit infix-Notation aufzurufen (Y % minus 1 enspricht minus(Y,1)) [7]. Um das boolsche Kriterium für die if Anweisung zu bekommen bedienen wir uns des ptr to fun-Operators. Mit den Lambdaausdrücken bietet die Bibliothek ein nützliches Feature und versucht die Lücke zwischen den funktionalen Programmiersprachen und C++ noch weiter zu schließen. 3 Zusammenfassung Bei FC++ handelt es sich um eine Bibliothek, die es ermöglicht in C++ funktional zu programmieren. In einigen kleinen Codebeispielen wurde deutlich wie FC++ funktionale Konzepte unterstützt. Insbesondere: • Functoide als das wesentliche Konzept polymorpher Programmierung und Funktionen höherer Ordnung. • Lazy Lists zur Erstellung von unendlichen Datenstrukturen. • Lambdaausdrücke, um anonyme Funktionen zur Laufzeit zu generieren. Die Entwickler setzten auch das Konzept der Monaden in FC++ um. Dabei handelt es sich um einen abstrakten Datentyp, der es ermöglicht, funktionale Programme logisch zu strukurieren. FC++ bietet eine gute Möglichkeit, sich experimentell mit der funktionalen Programmierung in einer objektorientierten Sprache auseinanderzusetzen und erlaubt dem C++ Programmierer, funktionale Techniken in sein Repertoire mit aufzunehmen. Die Autoren sind sich durchaus bewusst, dass FC++ in kommerzieller Softwareentwicklung nie Einzug halten wird. Sie versuchten die Möglichkeiten und Einschränkungen zu zeigen, die C++ in Bezug auf funktionale Programmierung hat. Die Syntax brachte bei der Entwicklung die geringsten Probleme, vielmehr ist es die C++ Typinferenz, die viele Probleme verursacht. Mit diesem Problem werden sich jedoch alle Autoren auseinandersetzen müssen, die auch in Zukunft versuchen werden C++ und funktionale Programmierung zu vereinen. 10 Literatur [1] C++: Documentation Function http://www.cplusplus.com/doc/tutorial/templates/. [2] FC++: The Functional C++ Library. nis/fc++/. Templates. http://www.cc.gatech.edu/ yan- [3] Konstantin Läufer. A framework for higher-order functions in C++. Berkeley, CA, USA, 1995. [4] Brian McNamara and Yannis Smaragdakis. Functional Programming in C++. College of Computing, Georgia Institute of Technology. http://www.cc.gatech.edu/ yannis/fc++/fc++.main.pdf. [5] Brian McNamara and Yannis Smaragdakis. Functional Programming in C++ using the FC++ Library. College of Computing, Georgia Institute of Technology. http://www.cc.gatech.edu/ yannis/fc++/fc++-sigplan.pdf. [6] Brian McNamara and Yannis Functional Programming with the FC++ Library. lege of Computing, Georgia Institute http://www.cc.gatech.edu/ yannis/fc++/fcpp-jfp.pdf. of [7] Brian McNamara and Yannis Syntax sugar for FC++: lambda, infix, monads, and more. lege of Computing, Georgia Institute of http://www.cc.gatech.edu/ yannis/fc++/fcpp-lambda.pdf. 11 Smaragdakis. ColTechnology. Smaragdakis. ColTechnology.