ERLANG (cont.) Funktionale Programmierung ERLANG: weitere Aspekte D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg c Sommer 2015, 10. April 2015, 2011–15 D.Rösner D. Rösner FP 2015 . . . 1 ERLANG (cont.) Gliederung 1 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen D. Rösner FP 2015 . . . 2 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Atome in ERLANG Atome . . . konstante Literale, die für sich selbst stehen ([CT09], p.19) syntaktische Konventionen: Atome starten mit einem Kleinbuchstaben oder sind in einfache Quotierungszeichen eingeschlossen Beispiele: person, einAtom, . . . ’Atom mit Blanks’, ’[email protected]’, . . . D. Rösner FP 2015 . . . 4 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Atome in ERLANG einzige Operation auf Atomen: Vergleiche Beispiele: 90> alpha < omega. true 91> alpha =< omega. true 92> alpha >= omega. false D. Rösner FP 2015 . . . 5 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Strings in ERLANG Zeichen werden in ERLANG als Integer dargestellt, Strings als Listen von Zeichen (d.h. Integer) 93> [65,66,67]. "ABC" 94> $A. 65 95> $a. 97 $ . . . liefert ganzzahligen Wert zu einem Zeichen D. Rösner FP 2015 . . . 7 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Strings in ERLANG Beachte: 103> [49,50,51]. "123" 104> $1. 49 105> "123" == 123. false vordefinierte Konversionsfunktionen (BIF): 106> list_to_integer("123"). 123 107> list_to_integer("123") == 123. true 109> integer_to_list(4711). "4711" D. Rösner FP 2015 . . . 8 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Pattern matching in ERLANG Pattern matching in ERLANG ist von Prolog inspiriert im Unterschied zu Haskell dürfen auch im Pattern Variable mehrfach vorkommen daher muss in solchen Fällen die Gleichheit der Werte nicht durch zusätzliche ‘guards’ geprüft werden D. Rösner FP 2015 . . . 10 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Pattern matching in Haskell allEqual :: Eq a => [a] -> Bool allEqual [] = True allEqual [_] = True allEqual (el1:el2:rest) = if el1 == el2 then allEqual (el2:rest) else False D. Rösner FP 2015 . . . 11 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Pattern matching in Erlang -module(allequal). -export([allequal/1]). allequal([]) -> true; allequal([_]) -> true; allequal([X,X|T]) -> allequal([X|T]); allequal([_,_|_]) -> false. D. Rösner FP 2015 . . . 12 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Pattern matching in Erlang -module(interval). -export([interval/2]). %interval(Low,High) when Low == High -> [High]; %% this guard can be captured in the pattern interval(High,High) -> [High]; interval(Low,High) when Low < High -> [Low] ++ interval(Low+1,High); interval(_,_) -> []. D. Rösner FP 2015 . . . 13 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Vergleich zwischen Erlang, Prolog und Haskell Aneinanderfügen zweier Listen als Relation in Prolog bzw. als Funktion in Erlang bzw. Haskell als Beispiel Bemerkungen: in allen Sprachen vordefiniert Haskell: ++ . . . Infix-Operator Erlang: ++ . . . Infix-Operator Prolog: append/3 D. Rösner FP 2015 . . . 15 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Funktion append in Haskell append :: [a] -> [a] -> [a] append [] ys = ys append (x:xs) ys = x:(append xs ys) Bemerkungen: strenge Typisierung Polymorphie D. Rösner FP 2015 . . . 16 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Funktion append in Erlang -module(append). -export([append/2]). append([],Y) -> Y; append([X|T],Y) -> [X|append(T,Y)]. D. Rösner FP 2015 . . . 17 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Relation append in Prolog append([],Y,Y). append([X|T],Y,[X|R]) :- append(T,Y,R). Bemerkungen: in unterschiedlicher Weise verwendbar D. Rösner FP 2015 . . . 18 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen da in Haskell grundsätzlich ‘lazy’ evaluiert wird, werden für unendliche Listen in Haskell keine zusätzlichen Sprachmittel benötigt Beispiel: fibgen a b = a:(fibgen b (a + b)) fibs = fibgen 0 1 Main> take 10 fibs [0,1,1,2,3,5,8,13,21,34] D. Rösner FP 2015 . . . 20 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Scheme werden gewöhnliche Listen – und andere Datenstrukturen – strikt (oder ’eager’) ausgewertet mit cons-stream können sog. Ströme gebildet werden D. Rösner FP 2015 . . . 21 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Ströme: Sprachmittel in SCHEME Konstruktor: cons-stream Selektoren: head, tail Beziehung: für bel. a,b und x: Wenn x ist (cons-stream a b), dann (head x) ist a und (tail x) ist b. Konstante: the-empty-stream Prädikat: empty-stream? D. Rösner FP 2015 . . . 22 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Ströme: Implementation Implementation von Strömen durch verzögerte Evaluation (delayed evaluation, lazy evaluation) in normalen Listen: car und cdr werden zur Konstruktionszeit evaluiert in Strömen: tail erst zur Zugriffszeit evaluieren (call-by-need) Spezialform delay: (delay <exp>) . . . liefert ein verzögertes Objekt, sog. promise, dass erst mit force zur Ausführung veranlasst wird (force <promise>) . . . veranlasst Ausführung von <promise> D. Rösner FP 2015 . . . 23 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Implementation cont. (cons-stream <a><b>) . . . Spezialform, die gleichwertig mit (cons <a> (delay <b>)) d.h. Strom wird als Paar dargestellt im cdr steht promise zur Berechnung des tail (define (head stream) (car stream)) (define (tail stream) (force (cdr stream))) D. Rösner FP 2015 . . . 24 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendlich lange Ströme Strom positiver ganzer Zahlen (define (integers-starting-from n) (cons-stream n (integers-starting-from (1+ n)))) (define integers (integers-starting-from 1)) Strom von Fibonacci-Zahlen (define (fibgen a b) (cons-stream a (fibgen b (+ a b)))) (define fibs (fibgen 0 1)) D. Rösner FP 2015 . . . 25 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendlich lange Ströme cont. Sieb des Eratosthenes (define (sieve stream) (cons-stream (head stream) (sieve (filter (lambda (x) (not (divisible? x (head stream)))) (tail stream))))) (define primes (sieve (integers-starting-from 2))) D. Rösner FP 2015 . . . 26 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang mit ‘lazy embedding’ lassen sich in Erlang unendliche Listen kreieren Variante 1: -module(lazy). -export([ints_from/1,take/2, add/2]). ints_from(N) -> fun() -> [N|ints_from(N+1)] end. ... D. Rösner FP 2015 . . . 27 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante 1: cont. ... take(N,Lazy) -> if N == 0 -> []; true -> [hd(Lazy()) | take(N-1,tl(Lazy()))] end. %% analog zu add-stream in Scheme add([], _) -> []; add(_,[]) -> []; add(Lazy1, Lazy2) -> fun() -> [hd(Lazy1()) + hd(Lazy2()) | add(tl(Lazy1()), tl(Lazy2()))] end. D. Rösner FP 2015 . . . 28 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang 1> c("C:/Daten/roesner/erlang/modules/lazy.erl"). {ok,lazy} 2> CC = lazy:add(lazy:ints_from(97),lazy:ints_from(1)). #Fun<lazy.1.109043180> 6> lazy:take(2,CC). "bd" D. Rösner FP 2015 . . . 29 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang 8> CC. #Fun<lazy.1.109043180> 9> CC(). [98|#Fun<lazy.1.109043180>] 10> tl(CC()). #Fun<lazy.1.109043180> D. Rösner FP 2015 . . . 30 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang 11> (tl(CC()))(). [100|#Fun<lazy.1.109043180>] Variante: 11> apply(tl(CC()),[]). [100|#Fun<lazy.1.109043180>] D. Rösner FP 2015 . . . 31 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante des ‘lazy embedding’ für unendliche Listen -module(lazy2). -export([ints_from/1, take/2, drop/2, add/2, fibgen/2, nth/2, map/2, filter/2]). ints_from(N) -> [N|fun() -> ints_from(N+1) end]. ... verzögert wird hier also nur der Listenrest Analogie zu cons-stream in Scheme D. Rösner FP 2015 . . . 32 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante des ‘lazy embedding’ für unendliche Listen ... % trafo: hd(Lazy()) -> hd(Lazy) % tl(Lazy()) -> apply(tl(Lazy),[]) take(N,Lazy) -> if N == 0 -> []; true -> [hd(Lazy) | take(N-1,apply(tl(Lazy),[]))] end. drop(N,Lazy) -> if N == 0 -> Lazy; true -> drop(N-1,apply(tl(Lazy),[])) end. ... D. Rösner FP 2015 . . . 33 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante des ‘lazy embedding’ für unendliche Listen ... add([], _) -> []; add(_,[]) -> []; add(Lazy1, Lazy2) -> [hd(Lazy1) + hd(Lazy2) | fun() -> add(apply(tl(Lazy1),[]),apply(tl(Lazy2),[]) ) end]. D. Rösner FP 2015 . . . 34 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante bei Implementierung des ‘lazy embedding’ für unendliche Listen % variant implementations of code from lazy2.erl ints_from(N) -> [N|fun() -> ints_from(N+1) end]. % trafo: from lazy.erl to lazy2.erl % % hd(Lazy()) -> hd(Lazy) % tl(Lazy()) -> apply(tl(Lazy),[]) %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% % additional: local var Cont for tl(Lazy), then Cont() take(N,Lazy) -> Cont = tl(Lazy), if N == 0 -> []; true -> [hd(Lazy) | take(N-1,Cont())] end. ... D. Rösner FP 2015 . . . 35 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante bei Implementierung des ‘lazy embedding’ für unendliche Listen ... % possibility: exploit pattern matching add([], _) -> []; add(_,[]) -> []; add([H1|TL1], [H2|TL2]) -> [H1 + H2 | fun() -> add(TL1(), TL2()) end]. nth(N, [H | LTail]) -> if N == 1 -> H; true -> nth(N-1, LTail()) end. map(F,[H | LTail]) -> [F(H) | fun() -> map(F, LTail()) end]. ... D. Rösner FP 2015 . . . 36 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Literatur: I Joe Armstrong. Programming Erlang – Software for a Concurrent World. The Pragmatic Bookshelf, Raleigh, North Carolina; Dallas, Texas, 2007. ISBN 1-9343560-0. Joe Armstrong, Robert Virding, Claes Wikström, and Mike Williams. Concurrent Programming in ERLANG – Second Edition. Pearson Education Ltd., Harlow, Essex GB, 1996. ISBN 0-13-508301-X; A preprint of Part I is available for download from http://www.erlang.org/download/erlang-book-part1.pdf. D. Rösner FP 2015 . . . 37 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen Literatur: II Francesco Cesarini and Simon Thompson. Erlang Programming – A Concurrent Approach to Software Development. O’Reilly Media, Inc., Sebastopol, CA, USA, 2009. ISBN 978-0-596-51818-91. D. Rösner FP 2015 . . . 38