Benutzer:WStephan/Dodge Ram

aus Wikipedia, der freien Enzyklopädie
Zur Navigation springen Zur Suche springen
Icon
Erscheinungsjahr: 1977
Designer: Ralph Griswold
Aktuelle Version: 9.4.3  (14. November 2005)
Typisierung: schwach, dynamisch
Wichtige Implementierungen: Icon
Dialekte: Unicon
Beeinflusst von: SNOBOL, siehe SNOBOL4
Beeinflusste: Python
http://www.cs.arizona.edu/icon/index.htm

Icon ist eine High-Level Programmiersprache, die mehrere Programmierparadigmen umfasst und mit SNOBOL, einer Sprache zum Verarbeiten von Zeichenketten, verwandt ist. Unter anderem unterstützt sie zielgerichtete Ausführung und bietet viele Möglichkeiten zur Verarbeitung von Zeichenketten und Textmuster. Icon war ursprünglich nicht objektorientiert, 1996 wurde jedoch eine objektorientierte Erweiterung namens Idol entwickelt, aus der später Unicon wurde.

Icon ist von der ALGOL-Klasse der strukturierten Programmiersprachen abgeleitet, weshalb seine Syntax C und Pascal stark ähnelt. Es verwendet wie Pascal, mit dem es enger verwandt ist, die :=-Syntax für Zuweisungen, das procedure-Schlüsselwort usw. Andererseits verwendet Icon auch, wie C, geschweifte Klammern, um logisch zusammengehörenden Code zu gruppieren und eine Prozedur mit dem Namen main, die ausgeführt wird, um das Programm zu starten.

Icon weist auch viele Gemeinsamkeiten mit Skriptsprachen auf: Variablen müssen nicht deklariert werden, Datentypen werden automatisch erkannt und Zahlen können automatisch in Zeichenketten umgewandelt werden und umgekehrt. Eine weitere Eigenschaft, die es mit vielen Skriptsprachen teilt, ist das Fehlen eines Zeichens, welches das Ende einer Zeile signalisieren würde. Stattdessen wird bei Zeilen, die nicht mit einem Semikolon enden, angenommen, dass ein solches vorhanden sei, sofern dies Sinn machen würde.

Prozeduren sind die grundlegenden syntaktischen Einheiten, aus denen Icon-Programme bestehen. Obwohl diese das Pascal-Namensschema verwenden, funktionieren sie eher wie C-Funktionen und können Werte zurückgeben.


procedure doSomething(aString)
  write(aString)
end

zielgerichtete Ausführung

[Bearbeiten | Quelltext bearbeiten]

Eines von Icons Grundkonzepten ist es, dass Kontrollstrukturen auf dem Erfolg oder Scheitern von Ausdrücken basiert. Im Gegensatz dazu basieren die meisten anderen Programmiersprachen auf logischen (Boole'schen) Operatoren. Dies hat zur Folge, dass zum Beispiel der Vergleich if a < b nicht mit wenn das Ergebnis des Vergleichs wahr ist, sondern vielmehr mit wenn der Ausdruck erfolgreich ist gleichzusetzen ist. In diesem Fall ist das Ergebnis jedoch dasselbe, da der "< Operator" erfolgreich ist, wenn der Vergleich wahr ist. Außerdem gibt der "< Operator" seinen zweiten Parameter zurück, wenn er erfolgreich war, wodurch Konstruktionen wie if a < b < c, die in den meisten anderen Sprachen nicht funktionieren, möglich sind.

Der Nutzen dieses Konzepts wird besser erkennbar, wenn man sich folgendes Beispiel anschaut:

if a := read() then write(a)

Der Beispielcode kopiert eine Zeile vom Standardinput zum Standardoutput. Da Icon aufgrund von Scheitern oder Erfolg wertet, funktioniert dieser Code auch dann, wenn read() einen Fehler auslöst, weil zum Beispiel der Stream nicht existiert. In diesem Fall wird der Ausdruck a := read() einfach scheitern, write wird nicht aufgerufen.

Erfolg und Scheitern werden durch Funktionen nach oben weitergereicht, sodass ein Fehler innerhalb einer verschachtelten Funktion auch die aufrufende Funktion scheitern lässt. Das folgende Beispielprogramm liest zuerst eine komplette Datei ein und gibt diese dann in einer einzigen Zeile aus:

while write(read())

Wenn der read()-Befehl, zum Beispiel am Ende der Datei, scheitert, wird write() ebenfalls fehlschlagen. Dies wird wiederum nach oben weitergereicht, was die while-Schleife abbricht. Der obige Code kommt also ohne Ausnahmebehandlung aus und funktioniert dennoch korrekt. Zum Vergleich ein Beispiel in Java-basiertem Pseudocode, der die gleiche Aufgabe erfüllt:


try {
  while ((a = read()) != EOF) {
    write(a);
  }
} catch (Exception e) {
  // tue nichts, Schleife beenden
}

In diesem Fall sind zwei Vergleiche notwendig, einer um das Ende der Datei festzustellen (EOF) und ein weiterer, um andere Fehler abzufangen. Da es Java im Gegensatz zu Icon nicht erlaubt, Fehler als logische Elemente zu vergleichen, muss stattdessen die try/catch-Syntax verwendet werden. try-Anweisungen bringen, auch für den Fall, dass kein Fehler auftritt, Geschwindigkeitseinbußen mit sich, die mit Icon vermieden werden.

In Icon wird dieses Konzept zielgerichtete Ausführung genannt, was sich darauf bezieht, dass die Ausführung fortgesetzt wird, bis ein Ziel erreicht wird. Im obigen Beispiel ist das Ziel, die ganze Datei zu lesen. Die read-Anweisung ist so lange erfolgreich, so lange es mehr Informationen zum Einlesen gibt. Sobald dies jedoch nicht mehr der Fall ist (wenn das Ende der Datei erreicht wird), scheitert sie. Das Ziel wird also direkt in der Sprache geschrieben, anstatt Anweisungen, die Rückgabewerte auswerten, oder ähnliche Konstrukte zu verwenden.

Expressions in Icon often return a single value, for instance, x < 5 will evaluate and succeed with the value 5 or fail. However several of the examples below rely on the fact that many expressions do not immediately return success or failure, returning values in the meantime. This drives the examples with every and to; every causes to to continue to return values until it fails.

This is a key concept in Icon, known as generators. Generators drive much of the loop functionality in the language, but do so more directly; the programmer does not write a loop and then pull out and compare values, Icon will do all of this for you.

Icon includes several generator-builders. The alternator syntax allows a series of items to be generated in sequence until one fails: 1 | "hello" | x < 5 can generate "1", "hello", and "5" if x is less than 5. Alternators can be read as "or" in many cases, for instance:

if y < (x | 5) then write("y=", y)

will write out the value of y if it is smaller than x or 5. Internally Icon checks every value from left to right until one succeeds or the list empties and it returns a failure. Remember that functions will not be called unless the calls within do not fail, so this example can be shortened to:

write("y=", (x | 5) > y)

Another simple generator is the to, which generates lists of integers; every write(1 to 10) will do exactly what it seems to. The bang syntax generates every item of a list; every write(!aString) will output each character of aString on a new line.

To demonstrate the power of this concept, consider string operations. Most languages include a function known as find or indexOf that returns the location of a string within another. Consider:

s = "All the world's a stage. And all the men and women merely players";
i = indexOf("the", s)

This code will return 4, the position of the first occurrence of the word "the". To get the next instance of "the" an alternate form must be used, i = indexOf("the", s, 5), the 5 at the end saying it should look from position 5 on. In order to extract all the occurrences of "the", a loop must be used...

s = "All the world's a stage. And all the men and women merely players";
i = indexOf("the", s)
while i != -1 {
  write(i);
  i =  indexOf("the", s, i+1);
}

Under Icon the find function is a generator, and will return the next instance of the string each time it is resumed before finally failing after it passes the end of the string. The same code under Icon can be written:

s := "All the world's a stage. And all the men and women merely players"
every write(find("the",s))

find will return the index of the next instance of "the" each time it is resumed by every, eventually passing the end of the string and failing. As in the prior example, this will cause write to fail, and the (one-line) every loop to exit.

Of course there are times where you deliberately want to find a string after some point in input, for instance, you might be scanning a text file containing data in multiple columns. Goal-directed execution works here as well, and can be used this way:

write(5 < find("the", s))

The position will only be returned if "the" appears after position 5, the comparison will fail otherwise, passing that failure to write() as before. There is one small "trick" to this code that needs to be considered: comparisons return the right hand result, so it is important to put the find on the right hand side of the comparison. If the 5 were placed on the right, 5 would be written.

Icon adds several control structures for looping through generators. The every operator is similar to while, looping through every item returned by a generator and exiting on failure:

 every k := i to j do
  write(someFunction(k))

Why use every instead of a while loop in this case? Because while re-evaluates the first result, but every produces all results. The every syntax actually injects values into the function in a fashion similar to blocks under Smalltalk. For instance, the above loop can be re-written this way:

every write(someFunction(i to j))

Users can build new generators easily using the suspend keyword:

procedure findOnlyOdd(pattern, theString)
  every i := find(pattern, theString) do
    if i % 2 = 1 then suspend i
end

This example loops over theString using find to look for pattern. When one is found, and the position is even, the location is returned from the function with suspend. Unlike return, suspend writes down where it is in the internal generators as well, allowing it to pick up where it left off on the next iteration.

Auch beim Umgang mit Zeichenketten ist die Skript-ähnliche Funktionsweise Icons sichtbar. Hier ist vor allem das Scan-System zu nennen, das wiederholt Funktionen auf eine Zeichenkette anwendet:

So ist s ? write(find("the")) eine Kurzform der schon vorher gezeigten Beispiele. In diesem Fall wird der zu testende Wert der find-Funktion außerhalb der Parameter und vor dem Fragezeichen plaziert. Icon-funktionen werden ganz bewusst so geschrieben, dass Testwerte in Parameterlisten leicht erkannt und auf diese Art und Weise herausgefiltert werden können.

Other structures

[Bearbeiten | Quelltext bearbeiten]

Icon strings are simply lists of characters, similar to their partners in C. Icon also allows the user to easily construct their own lists (or arrays):

aCat := ["muffins", "tabby", 2002, 8]

The items within a list can be of any sort, including other structures. To quickly build larger lists, Icon includes the list generator; i := list(10, "word") generates a list containing 10 copies of "word".

Like arrays in other languages, Icon allows items to be looked up by position; weight := aCat[4]. Also remember the bang-syntax, every write(!aCat) will print out four lines, each with one element. Icon includes stack-like functions, push and pop to allow them to form the basis of stacks and queues.

Icon also includes functionality for sets and tables (known as hashes, associative arrays, dictionaries, etc.):

symbols := table(0)
symbols["there"] := 1
symbols["here"] := 2

This code creates a table that will use zero as the default value of any unknown key. It then adds two items into it, with the keys "there" and "here", and values 1 and 2.

Das Standardwerk für Icon:

  • Ralph E. Griswold: Icon Programming Language, 3rd Edition. Coriolis Group Books, ISBN 1-57398-001-3

Es wird zurzeit nicht mehr gedruckt, kann aber als PDF heruntergeladen werden.