Programming Languages From Hell Proseminar im

Werbung
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.
Herunterladen