Wir arbeiten mit SML/Standard ML. In der New Jersey Implementierung [Wiki], [Projekt Seite].
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).
cd
into the extracted directorymakepkg
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.
Beide immer verwendbar, aber nicht mischbar.
ACHTUNG: o
nicht verwenden. Ist bereits Infix Operation der Komposition.
Typ | Rechnen ('a * 'a -> 'a ) | Vergleichen ('a * 'a -> bool ) |
||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
int | ~ | + | - | * | div | mod | = | <> | < | > | <= | >= |
||
real | ~ | + | - | * | / | Real.== | Real.!= | < | > | <= | >= |
|||
bool | not | = | <> | |||||||||||
string | ^ | = | <> | < | > | <= | >= |
~42;
OK~~42;
Fehler: „unbound variable or constructor: ~~“~ ~42;
OK~ ~ 42;
Fehler: „operator and operand don't agree [overload]“~(~42);
OK~(~ 42);
OK~ (~42);
OK~ (~ 42);
OK+ 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:
fun f(x : real) = x + x;
fun f(x) : real = x + x;
fun f(x : real) : real = x + x;
Funktionen | Int.abs | Int.min | Int.max | Int.sign | real() : int -> real | Real.fromInt() : int -> real | Int.toString() |
---|
Führende 0 erlaubt.
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) |
---|
.42
nicht erlaubttrunc()
entspricht floor()
für positive Zahlentrunc()
entspricht ceil()
für negative ZahlenReal.compare : real * real -> order
order
= LESS
/EQUAL
/GREATER
Werte | true | false |
---|
Operationen | andalso | orelse |
---|
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
Werte | #„a“ |
---|
Funktionen | chr() | ord() | str() |
---|
- fun f() = 42;
val f = fn : unit → int
- fun f(x) = ();
val f = fn : 'a → unit
(1, „a“)
int * real
(((3))) → 3
(eins, zwei) = (1, 2)
(((3))) = 3
val (a:int, b) = someTupel
val a = #2 someTupel
()
{ b = 1.0, a = „foo“ } : {a:real, b:string }
{a = 1.0, b = 2.0} <> {aaa = 1.0, bbb = 2.0}
{a:int, b:real}
{a = 1.0, b = 2.0} = {b = 2.0, a = 1.0}
#a {a = 1.0}
val {a, b} = {a = 1.0, b = 2.0}
val {c=a, d=b} = {c=„a“, d=„b“}
val {1=a, 2=b} = („a“, „b“)
val (1=a, 2=b) = („a“, „b“)
FEHLER{2=„b“, 1=„a“} → („a“, „b“)
{2=„b“, 1=„a“} → ()
{2=„b“} → {2=„b“}
{2=„b“, 1=„a“} = („a“, „b“)
{1=„a“} = {1=„a“}
#asd
ist eine Funktion, läst sich also auch so schreiben (Math.sqrt o #y) {x = 1.2, y = 3,4}
.
[1, 2, 3] : int list
int list
nil
benötigt) nil : 'a list
a :: b :: c :: [d, e] = a :: (b :: (c :: [d,e]))
val [a, b, c] = [3, 2, 1];
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)!
Bei der Funktion ist der erste Parameter immer der listen Wert!
foldl
geht von links durch die Liste (fängt links an)foldr
geht von rechts durch die Liste (fängt von rechts an)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
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) |
- NONE; NONE : 'a option - NONE : int option; NONE : int option - SOME 4.2; SOME 4.2 : real option
print()
ist synonym für TextIO.print()
TextIO.vector
verhält sich wie string
TextIO.elem
verhält sich wie char
TextIO
: char option / stringBinIO
: 8 BitWas | 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 |
Aufgaben:
Arten:
Statisch typisierte Sprache = Ausschließlich statische Typprüfung = SML
Vorteile:
type foo = int * int
type 'a bar = 'a list
int bar
(2, 3) : foo
(2, 3) : (int * int)
datatype Farbe = Rot | Blau
Farbe.Rot
)datatype Farbe = Rot | Blau
datatype Koordinate = Polar of real * real | Kart of real * real
Polar(1.0, 2.0)
(Kein currying!)datatype 'a dt = Foo of 'a list | Null
Foo([1, 2]) : int list dt
rec
) datatype Baum = Blatt | Knoten of Baum * Baum
val
, exception
, fun
, …)val Red = - : color
(* 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;
Struktur | Signatur | Funktor | |
---|---|---|---|
SML Analogie | Wert | Typ | Funktion |
OOP Analogie | Klasse | Interface | Template |
Beinhaltet | Definitionen | Spezifikationen | – |
Namenskonvention | Name | NAME | Name |
Struktur.deklaration
structure Name = struct <dec> <dec> ... end;
Signature-Constraint mit
structure Name : NAME =
structure Name : sig <spec> <spec> … end =
view / sicht: Unterspezifizierte Signatur
signature NAME = sig <spec> <spec> ... end;
Signatur Spezifikationen:
val foo : int
val foo : int -> int
type foo
type foo = int
eqtype foo
datytype foo = value(x) | …
exception foo of int
Implementierbar mit | ||||
---|---|---|---|---|
type | datatype | abstype |
||
Spezifikation | type bla | X | X | X |
type bla = int | X | |||
eqtype bla | X | X | ||
datytype bla = … | X |
Structure | Funktor |
---|---|
structure Name = | functor Name(param : SIGNATURE) = |
struct <dec> <dec> end |
Erzeugen einer konkreten Struktur:
structure NameName = Name(OtherName)
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!!!!
'a
(alpha)''a
: Typ mit =
definiert (also z.B. keine Funktion)int list
(warum ist das keine typ konstante?)*
, ->
, …. (Bindet Schwächer) meist postfix oder infixAusdruck : Typausdruck
Typkonstruktor | (Wert-)Konstruktor | ||
---|---|---|---|
Muster | Schreibweise | Beispiel | |
. list | Linksassoziativ | (('a list) list) | . :: . |
nil |
|||
. * . | Infix | ( . , . ) |
|
{ . : . , . : . } | { . = . , . = . } |
||
. -> . (Rechtsassoziativ) | Rechtsassoziativ | (int -> (int -> int)) | fn . => . |
Funktion $\subseteq$ Prozedur (D.h. nicht jede Prozedur ist auch eine Funktion, aber jede Funktion ist eine Prozedur)
Funktion:
fun f(x) = x
f(8)
Prozeduren:
use()
.()
zurück.fun f(a, b) = a+b; f(1, 2);
fun f{a, b} = a+b; f{a=1, b=2};
val f = fn x ⇒ 42
val rec f = fn x ⇒ 42
nur mit fn
fun f(x) = 42
Hat implizites rec
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 io fun x io y = ... val (op io) = fn (x, y) => ...
infix foo; fun p1 foo p2 = p1 + p2;
infix 3 foo
. Präzedenz = 3 (default: 0; bereich: 0 - 9)infix
= liksassoziativ; infixr
= rechtsassoziativinfix op1 op2 op3
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)
Infix Operator o
. Variablen/Funktionen dürfen nicht o
heißen.
(f o g)(x) = f(g(x))
(f o g)(x) = g(f(x))
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;
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;
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
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
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);
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;
Substitutionsmodel: Alles wird ersetzt, Reihenfolge bleibt offen (Nur für Referenzentransparente Sprachen sinvoll).
Terminieren alle Reihenfolgen, kommt das gleiche Ergebnis raus.
The SML way, bis auf sonderausdrücke.
n = 1
n >= 0
n ⇐ 1
Parametervorkommen werden, bis auf eins, durch Zeiger, auf das eine, ersetzt. ⇒ Parameter werden maximal einmal Ausgewertet.
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>
…. 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?
Bislang verwendete Funktionen
it
ist eine art default Vairable (wörtlich zu nehmen „es“)use(„file.sml“)
hd
= head?; nicht aus VL)tl
= tail?; nicht aus VL)'a
ist ein Polymorpher typ parameter (d.h. er wird wenn der typ ausgegeben wird werden abhängige type a, b, c, … genannt)tl; it myList;
funktioniert!else
bie if
_
default bei prädikaten immer am Ende.val xxx = ( yyy )
Implizite klammerung nach dem ersten “=„ oder dem nach „val“ (prüfen) und besondere bedeutung (zuweisung).fun a(p1); fun b(p2);
(* … *)
Baumdurchläufe:
Präfix collect bei Blatt mit zwei daten inkonsistent. siehe Folien 7.4, Seite 42
val a = 1; val a = 2;
val
: pos - 1fun
und val rec
: posval … ; val … ;
(lokale) Umgebung wird nacheinander erweitert.val .. and …
(lokale) Umgebung wird gleichzeitig erweitert. (Es wird gesamelt, nötig für Wechselseitige rekursion).val
, fun
if … then … else …
, case
, …andalso
, orelse
(if a > 42 then abs else quadrat)(b)
<Muster> => <Ausdruck>
<Angleichungsregel> | <Angleichungsregel> | <Angleichungsregel>
case <Ausdruck> of <Angleichungsmodell>
val (a, b) = (1, 2)
fn <Angleichungsmodell>
fun …
Warning: match nonexhaustive
⇒ mögliche Laufzeitfehler._
…
val {1=a, 3=b, …} = (11, 22, 33, 44)
L1 as L2
D as (N, V)
Beweise:
exn
exception foo
exception bar of string * int
raise foo
raise bar(„You failed“, 1337)
handle <Muster 1> => <Ausdruck 1> | <Muster 2> => <Ausdruck 2>
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"
Was | Wie |
---|---|
Erstellen | val foo = ref 42 |
Dereferenzieren | !foo |
Neu zuweisen | foo := 21 |
ref
ist eine Funktionref nil
OK: ref (nil : string list)
)ref 42 <> ref 42
):=
ist ein Infix Operator()
'a ref * 'a -> unit
pointer1 = pointer2
⇒ !pointer1 = !pointer2
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;