Inhaltsverzeichnis

ProMo

SMl NJ

Wir arbeiten mit SML/Standard ML. In der New Jersey Implementierung [Wiki], [Projekt Seite].

Install on Arch

A new up to date PKGBUILD can be found in a Arch Linux Forum post. There is also an AUR package from 2010.

The installation process for the AUR package is as usual (don't do it as root).

  1. Download the tarball (Not the PKGBUILD)
  2. untar the package
  3. cd into the extracted directory
  4. Build the package with makepkg
  5. Install the package with sudo pacman -U *pkg.tar.xz

The installation process of the forum package is the same expect for the steps 1 and 2, it can be omitted.

Tutorials and help

Identifyer

Beide immer verwendbar, aber nicht mischbar.

ACHTUNG: o nicht verwenden. Ist bereits Infix Operation der Komposition.

Typen

Typ Rechnen ('a * 'a -> 'a) Vergleichen ('a * 'a -> bool)
int ~ + - * div mod = <> < > <= >=
real ~ + - * / Real.== Real.!= < > <= >=
bool not = <>
string ^ = <> < > <= >=

+ ist Links assiziativ: 1 + 2 + 3 = (1 + 2) + 3

Implizites int wenn nicht allgemein genug für 'a aber zu unspezifisch für einen Typ. Z.B. ist fun f(x) = x + x vom Typ int * int -> int und nicht vom Typ 'a * 'a -> 'a. Alternativen sind:

int

Funktionen Int.abs Int.min Int.max Int.sign real() : int -> real Real.fromInt() : int -> real Int.toString()

Führende 0 erlaubt.

real

Wete 123.4E~4 123.4e5 000123.4e0005 nan
Nicht schreibbar
inf
Nicht schriebbar
Funktionen Real.compare(4.2, 9.9) floor() ceil() trunc() round(1.5)

bool

Werte true false
Operationen andalso orelse

string

Werte \n \t \\ \„ “„
Funktionen size() String.sub(„abc“, 2) = #„b“

„aaa\<whitespace Zeichen z.B. Zeilenumbruch>\bbb“ also z.B. bei der Eingabe:

- "aaa\

   \bbb";
it = "aaabbb" : string

char

Werte #„a“
Funktionen chr() ord() str()

unit

- fun f() = 42;
val f = fn : unit → int

- fun f(x) = ();
val f = fn : 'a → unit

Vektor/Tupel

Verbund/Record

#asd ist eine Funktion, läst sich also auch so schreiben (Math.sqrt o #y) {x = 1.2, y = 3,4}.

List

Wete nil
Funktionen tl() hd() length() rev() List.last() List.nth([…], 42) map fn list
Keine Klamern!
foldl fn start list
Keine Klamern!
foldr fn start list
Keine Klamern!
list @ list
infix!

fold[l/r] hatt 3 Parameter! Startwert nicht vergessen! Liste erst am schluss (macht mit unvolständigen Parametern und currying sinn)!

  1. Funktion
  2. Start Wert
  3. Liste

Bei der Funktion ist der erste Parameter immer der listen Wert!

  1. Wert aus der Liste
  2. Agregiertert Wert

Achtung currying: Richtig Klammern

- foldl (fn (a, b) => let val t = print("l = "^a^"\tr = "^b^"\n") in a^b end) "#" (["1", "2", "3"]);
l = 1	r = #
l = 2	r = 1#
l = 3	r = 21#
val it = "321#" : string
- foldr (fn (a, b) => let val t = print("l = "^a^"\tr = "^b^"\n") in a^b end) "#" (["1", "2", "3"]);
l = 3	r = #
l = 2	r = 3#
l = 1	r = 23#
val it = "123#" : string

Array

Vektor Array
Elemente fix Elemente Veränderbar
Was Wie
Anlegen Array.array(3, 0)
[|0, 0, 0|] : int array
Auslesen Array.sub(a, 1)
Ändern Array.update(a, 1, 42)
() : unit
Länge Array.length(a)
List → Array Array.fromList(list)

option

- NONE;
NONE : 'a option
 
- NONE : int option;
NONE : int option
 
- SOME 4.2;
SOME 4.2 : real option

IO

Was Output Input
Typ .outstream .instream
Öffnen .openOut(„datei“)
.stdOut
.openIn(„datei“)
.stdIn
Transferieren .output(stream, „Text“) : unit .input1(stream) : TextIO.elem option
.input42(stream) : TextIO.vector
.input(stream) : TextIO.vector
Flush .flushOut(stream) : unit
Schließen .closeOut(stream) : unit .closeIn(stream) : unit

Typprüfung

Aufgaben:

Arten:

Statisch typisierte Sprache = Ausschließlich statische Typprüfung = SML

Vorteile:

Typdefinition

Type

Datatype

Abstype

(* Vergleiche mit type Deklaraton:
type    color = rgb of int * int * int
*)
abstype color = rgb of int * int * int
with
  val red  = rgb(255, 0,   0);
  val blue = rgb(  0, 0, 255);
 
  exception fail;
 
  fun makeGreen(x) = rgb(0, x, 0);     (* Wertkonstruktor nur hier innerhalb verwendbar *)
end;
 
(* Zugriffüber globalen name space *)
makeGreen(20);
red;

Module

Struktur Signatur Funktor
SML Analogie Wert Typ Funktion
OOP Analogie Klasse Interface Template
Beinhaltet Definitionen Spezifikationen
Namenskonvention Name NAME Name

Structure

structure Name =
 
  struct
    <dec>
    <dec>
    ...
  end;

Signature-Constraint mit

view / sicht: Unterspezifizierte Signatur

Signature

signature NAME =
 
  sig
    <spec>
    <spec>
    ...
  end;

Signatur Spezifikationen:

Implementierbar mit
type datatype abstype
Spezifikation type bla X X X
type bla = int X
eqtype bla X X
datytype bla = … X

Funktor

Structure Funktor
structure Name =
functor Name(param : SIGNATURE) =
struct
<dec>
<dec>
end

Erzeugen einer konkreten Struktur:

structure NameName = Name(OtherName)

Polymorphie

Polymorphe Typen (Polytyp): 'a oder 'a list gegenteil: Monotyp

Das gibt einen Fehler da der Typ des ausdrucks bei der Anwendung nicht festgestelt werden kann.

nil@nil;
Polymorphie Überladen
Gleicher name Gleicher name
Gleicher Algorithmus Verschiedene Algorithmen
Flexibler typ Fester typ
Auch „parametrischer Polymorphie“ Auch „ad hoc–Polymorphie“

Kapitel 5.4 in den Folien Lesen!!!!

Typkonstruktor (Wert-)Konstruktor
Muster Schreibweise Beispiel
. list Linksassoziativ (('a list) list) . :: .
nil
. * . Infix ( . , . )
{ . : . , . : . } { . = . , . = . }
. -> . (Rechtsassoziativ) Rechtsassoziativ (int -> (int -> int)) fn . => .

Strukturelemente

Funktion / Prozedur

Funktion $\subseteq$ Prozedur (D.h. nicht jede Prozedur ist auch eine Funktion, aber jede Funktion ist eine Prozedur)

Funktion:

Prozeduren:

Ordnung

Parameter

Positionsparameter
fun f(a, b) = a+b;
f(1, 2);
Rollenparameter
fun f{a, b} = a+b;
f{a=1, b=2};

Schreibart

Lambda Funktion
Normale Funktion
fun f(x) = 42

Hat implizites rec

Currying

Currying ⇒ curried Funktion:

fun f x y = ...
val f = fn x => fn y => ...

ACHTUNG: val f = fn x y ⇒ … ist nicht möglich!

ACHTUNG: Einzelne Parameter richtig Klamern

Infix

infix io
fun x io y = ...
val (op io) = fn (x, y) => ...
infix 0 before
infix 3 o :=
infix 4 = <> > < >= <=
infixr 5 :: @
infix 6 + - ^
infix 7 * / div mod quot rem

op wandelt Infix in Präfix Funktion.

ACHTUNG bei * operator: Fehler (op *) da *) Einde eines Komentars ist. Korrekt: (op * ) (mit Leerzeichen)

Komposition

Infix Operator o. Variablen/Funktionen dürfen nicht o heißen.

Misc

f(a, b, c) ist Ein-Stellige Funktion. Mit dem einen Parameter, dem Tupel (a, b, c). Denn es kann auch wie follgt Aufgerufen werden:

val params = (1, 2, 3);
f params;

http://www.mpi-sws.org/~rossberg/sml.html

Auswahl

else-Teil muss immer angegeben werden.

val f = fn n => if n = 42 then true else false;
fun f(n) = if n = 42 then true else false;
val f = fn 42 => true
         | n  => false;
fun f(42) = true
  | f(n)  = false;

let / local

local
  statement;
  statement;
  ...
  statement
in
  statement
end

Let ist nötig wenn ein Funktionsparameter aus in … in let … verwendet werden muss.

let
  statement;
  statement;
  ...
  statement
in
  expression
end

val ... and ...

Mit

val x = 2;
let
  val x = 2*x
  val x = 3*x
in
  x
end;

Ergibt 12, da jedes val alles einzeln Auswertet und Zuweist (mit dem x der jeweils vorherigen Deklaration).

let
  val x = 2*x and y = 3*x
in
  x+y
end;

Ergibt 10, da val … and … alles auf einmal Auswertet und dann Zuweist (erst alles auswerten, dann alles auf einmal zuweisen).

let
  val x = 2*x and x = 3*x
in
  x
end;

stdIn:2.5-2.28 Error: duplicate variable in pattern(s): x

Rekursion

Wechselseitige rekursion

val … and … muss sein.

val rec a = fn 0 => false
             | n => b(n-1)
and
        b = fn 0 => true
             | n => a(n-1);
fun a(0) = false
  | a(n) = b(n-1)
and
     b(0) = true
   | b(n) = a(n-1);

Endrekursive Funktion

Endrekursive Funktion

Kein rekursiver Aufruf in einem zusammengesetzten Ausdruck (ausgenommen Fallunterscheidungen wie if .. then .. else oder case).

Die Werte die für den nächsten Iterationsschritt benötigt werden, werden als Parameter übergeben und sind kein Rückgabewert (einer rekursiven Funktion).

Verhindert Speicherverschwendung durch unvolendete Rechnungen (Um die berechnung ab zu schließen muss nicht nochmal die rekursive funktion aufgerufen werden).

Beispiel

local
  fun qAux(sum, 0) = sum
    | qAux(sum, n) = qAux(sum + (n mod 10), n div 10)
in
  fun q(n) = qAux(0, n)
end;

Auswertung

Substitutionsmodel: Alles wird ersetzt, Reihenfolge bleibt offen (Nur für Referenzentransparente Sprachen sinvoll).

Terminieren alle Reihenfolgen, kommt das gleiche Ergebnis raus.

Applikative Reihenfolge

The SML way, bis auf sonderausdrücke.

Reihenfolge

  1. Parameter
  2. Funktion

Alternativnamen

Parameterauswertung

n = 1

Normale Reihenfolge

Reihenfolge

  1. Funktion
  2. Parameter

Alternativnamen

Parameterauswertung

n >= 0

Verzögerte Auswertung

Reihenfolge

  1. Funktion
  2. Parameter

Parameterauswertung

n ⇐ 1

Parametervorkommen werden, bis auf eins, durch Zeiger, auf das eine, ersetzt. ⇒ Parameter werden maximal einmal Ausgewertet.

Sonderausdrücke

if <1> then <2a> else <2b>

case <1> of <a> => <2a>
          | <b> => <2b>
          | <c> => <2c>
          | <d> => <2d>
          | <e> => <2e>

<1> orelse <2>

<1> andalso <2>

Bindung

…. Was hat statische/dynamische bindung mit dem vorhandensein von scopes (und überschatten zu tun? Zu sehen am follgenden beispiel:

val n = 2;
fun foo() = n;
val n = 3;
fun bar(n) = n + foo();
bar(4);

statisch ist eigentlich semi-statisch, da parameter dynamisch bleiben müssen. statisch ohen scope mölich?

Misc

Funktionen

Bislang verwendete Funktionen

Mein Spickzettel

Baumdurchläufe:

Präfix collect bei Blatt mit zwei daten inkonsistent. siehe Folien 7.4, Seite 42

Umgebung

Ausdruck

Variablen

(if a > 42 then abs else quadrat)(b)

Pattern Matching

Beweise:

Exceptions

Ausnahmepaket im Substitutionsmodel

((raise foo(42)) + 3) handle foo(x) => "Failed"
($[foo(42)] + 3) handle foo(x) => "Failed"
$[foo(42)] handle foo(x) => "Failed"
"Failed"

Referenzen

Was Wie
Erstellen val foo = ref 42
Dereferenzieren !foo
Neu zuweisen foo := 21

Schleifen

while <Ausdruck : bool> do <Ausdruck>
fun sum(n) =
  let
    val sum = ref 0;
    val cnt = ref n;
  in
    while !cnt <> 0 do (
      sum := !sum + !cnt;
      cnt := !cnt -1   (* Hier KEIN ";" *)
    );
    !sum   (* Hier KEIN ";" *)
  end;