ERLANG (cont.) ERLANG (cont.) Gliederung Funktionale Programmierung ERLANG: weitere Aspekte 1 D. Rösner Institut für Wissens- und Sprachverarbeitung Fakultät für Informatik Otto-von-Guericke Universität Magdeburg ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen c Sommer 2015, 10. April 2015, 2011–15 D.Rösner D. Rösner FP 2015 . . . ERLANG (cont.) D. Rösner FP 2015 . . . 1 Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Atome in ERLANG 2 Atome Strings Pattern matching Vergleich Unendliche Listen Atome in ERLANG Atome . . . konstante Literale, die für sich selbst stehen ([CT09], p.19) syntaktische Konventionen: einzige Operation auf Atomen: Vergleiche Beispiele: 90> alpha < omega. true 91> alpha =< omega. true 92> alpha >= omega. false 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 D. Rösner FP 2015 . . . 5 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Strings in ERLANG Atome Strings Pattern matching Vergleich Unendliche Listen Strings in ERLANG Beachte: 103> [49,50,51]. "123" 104> $1. 49 105> "123" == 123. false 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 vordefinierte Konversionsfunktionen (BIF): 106> list_to_integer("123"). 123 107> list_to_integer("123") == 123. true $ . . . liefert ganzzahligen Wert zu einem Zeichen 109> integer_to_list(4711). "4711" D. Rösner FP 2015 . . . ERLANG (cont.) 7 Atome Strings Pattern matching Vergleich Unendliche Listen D. Rösner FP 2015 . . . ERLANG (cont.) Pattern matching in ERLANG 8 Atome Strings Pattern matching Vergleich Unendliche Listen Pattern matching in Haskell allEqual :: Eq a => [a] -> Bool Pattern matching in ERLANG ist von Prolog inspiriert allEqual [] = True im Unterschied zu Haskell dürfen auch im Pattern Variable mehrfach vorkommen allEqual [_] = True daher muss in solchen Fällen die Gleichheit der Werte nicht durch zusätzliche ‘guards’ geprüft werden D. Rösner FP 2015 . . . allEqual (el1:el2:rest) = if el1 == el2 then allEqual (el2:rest) else False 10 D. Rösner FP 2015 . . . 11 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Pattern matching in Erlang Pattern matching in Erlang -module(interval). -export([interval/2]). -module(allequal). -export([allequal/1]). %interval(Low,High) when Low == High -> [High]; %% this guard can be captured in the pattern allequal([]) -> true; allequal([_]) -> true; allequal([X,X|T]) -> allequal([X|T]); allequal([_,_|_]) -> false. D. Rösner FP 2015 . . . ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen interval(High,High) -> [High]; interval(Low,High) when Low < High -> [Low] ++ interval(Low+1,High); interval(_,_) -> []. 12 D. Rösner FP 2015 . . . Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Vergleich zwischen Erlang, Prolog und Haskell 13 Atome Strings Pattern matching Vergleich Unendliche Listen Funktion append in Haskell Aneinanderfügen zweier Listen als Relation in Prolog bzw. als Funktion in Erlang bzw. Haskell als Beispiel Bemerkungen: append :: [a] -> [a] -> [a] append [] ys = ys in allen Sprachen vordefiniert append (x:xs) ys = x:(append xs ys) Haskell: ++ . . . Infix-Operator Erlang: ++ . . . Infix-Operator Prolog: append/3 Bemerkungen: strenge Typisierung Polymorphie D. Rösner FP 2015 . . . 15 D. Rösner FP 2015 . . . 16 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Funktion append in Erlang Atome Strings Pattern matching Vergleich Unendliche Listen Relation append in Prolog -module(append). -export([append/2]). append([],Y,Y). append([X|T],Y,[X|R]) :- append(T,Y,R). append([],Y) -> Y; append([X|T],Y) -> [X|append(T,Y)]. Bemerkungen: in unterschiedlicher Weise verwendbar D. Rösner FP 2015 . . . ERLANG (cont.) 17 D. Rösner FP 2015 . . . Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendliche Listen 18 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: in Scheme werden gewöhnliche Listen – und andere Datenstrukturen – strikt (oder ’eager’) ausgewertet mit cons-stream können sog. Ströme gebildet werden 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 D. Rösner FP 2015 . . . 21 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Ströme: Sprachmittel in SCHEME Atome Strings Pattern matching Vergleich Unendliche Listen Ströme: Implementation Implementation von Strömen durch verzögerte Evaluation (delayed evaluation, lazy evaluation) Konstruktor: cons-stream in normalen Listen: car und cdr werden zur Konstruktionszeit evaluiert 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. 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 Konstante: the-empty-stream Prädikat: empty-stream? (force <promise>) . . . veranlasst Ausführung von <promise> D. Rösner FP 2015 . . . ERLANG (cont.) 22 Atome Strings Pattern matching Vergleich Unendliche Listen D. Rösner FP 2015 . . . ERLANG (cont.) Implementation cont. 23 Atome Strings Pattern matching Vergleich Unendliche Listen Unendlich lange Ströme Strom positiver ganzer Zahlen (cons-stream <a><b>) . . . Spezialform, die gleichwertig mit (cons <a> (delay <b>)) (define (integers-starting-from n) (cons-stream n (integers-starting-from (1+ n)))) (define integers (integers-starting-from 1)) d.h. Strom wird als Paar dargestellt im cdr steht promise zur Berechnung des tail Strom von Fibonacci-Zahlen (define (head stream) (car stream)) (define (fibgen a b) (cons-stream a (fibgen b (+ a b)))) (define (tail stream) (force (cdr stream))) (define fibs (fibgen 0 1)) D. Rösner FP 2015 . . . 24 D. Rösner FP 2015 . . . 25 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendlich lange Ströme cont. Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Sieb des Eratosthenes (define (sieve stream) (cons-stream (head stream) (sieve (filter (lambda (x) (not (divisible? x (head stream)))) (tail stream))))) 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. (define primes (sieve (integers-starting-from 2))) ... D. Rösner FP 2015 . . . ERLANG (cont.) 26 Atome Strings Pattern matching Vergleich Unendliche Listen D. Rösner FP 2015 . . . ERLANG (cont.) Unendliche Listen in Erlang 27 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 . . . 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" 28 D. Rösner FP 2015 . . . 29 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendliche Listen in Erlang 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 . . . ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen 11> (tl(CC()))(). [100|#Fun<lazy.1.109043180>] Variante: 11> apply(tl(CC()),[]). [100|#Fun<lazy.1.109043180>] 30 D. Rösner FP 2015 . . . Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendliche Listen in Erlang 31 Atome Strings Pattern matching Vergleich Unendliche Listen Unendliche Listen in Erlang Variante des ‘lazy embedding’ für unendliche Listen ... Variante des ‘lazy embedding’ für unendliche Listen % trafo: hd(Lazy()) -> hd(Lazy) % tl(Lazy()) -> apply(tl(Lazy),[]) -module(lazy2). -export([ints_from/1, take/2, drop/2, add/2, fibgen/2, nth/2, map/2, filter/2]). take(N,Lazy) -> if N == 0 -> []; true -> [hd(Lazy) | take(N-1,apply(tl(Lazy),[]))] end. ints_from(N) -> [N|fun() -> ints_from(N+1) end]. ... verzögert wird hier also nur der Listenrest drop(N,Lazy) -> if N == 0 -> Lazy; true -> drop(N-1,apply(tl(Lazy),[])) end. ... Analogie zu cons-stream in Scheme D. Rösner FP 2015 . . . 32 D. Rösner FP 2015 . . . 33 ERLANG (cont.) Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendliche Listen in Erlang 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 Variante des ‘lazy embedding’ für unendliche Listen ints_from(N) -> [N|fun() -> ints_from(N+1) end]. ... add([], _) -> []; add(_,[]) -> []; add(Lazy1, Lazy2) -> [hd(Lazy1) + hd(Lazy2) | fun() -> add(apply(tl(Lazy1),[]),apply(tl(Lazy2),[]) ) end]. D. Rösner FP 2015 . . . ERLANG (cont.) 34 % 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 . . . Atome Strings Pattern matching Vergleich Unendliche Listen ERLANG (cont.) Unendliche Listen in Erlang Atome Strings Pattern matching Vergleich Unendliche Listen Literatur: I Variante bei Implementierung des ‘lazy embedding’ für unendliche Listen Joe Armstrong. Programming Erlang – Software for a Concurrent World. The Pragmatic Bookshelf, Raleigh, North Carolina; Dallas, Texas, 2007. ISBN 1-9343560-0. ... % possibility: exploit pattern matching add([], _) -> []; add(_,[]) -> []; add([H1|TL1], [H2|TL2]) -> [H1 + H2 | fun() -> add(TL1(), TL2()) end]. 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. 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 . . . 35 36 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