Przygotował: Jacek Sroka. Scala Wprowadzenie

Podobne dokumenty
Przygotował: Jacek Sroka. JNP 3 język Scala

Samouczek Scali dla programistów Javy

Programowanie obiektowe

Język programowania Scala / Grzegorz Balcerek. Wyd. 2. Poznań, cop Spis treści

Scala. Obiektowo-funkcyjny język programowania. Zbyszek Skowron

Platformy Programistyczne Podstawy języka Java

Klasy abstrakcyjne, interfejsy i polimorfizm

Kurs programowania. Wstęp - wykład 0. Wojciech Macyna. 22 lutego 2016

Kurs programowania. Wykład 1. Wojciech Macyna. 3 marca 2016

PARADYGMATY PROGRAMOWANIA Wykład 4

Kurs WWW. Paweł Rajba.

Programowanie w Internecie. Java

Wykład 7: Pakiety i Interfejsy

Dokumentacja do API Javy.

Kurs programowania. Wykład 3. Wojciech Macyna. 22 marca 2019

JavaScript funkcyjność

Java: kilka brakujących szczegółów i uniwersalna nadklasa Object

Programowanie obiektowe

Język JAVA podstawy. Wykład 3, część 3. Jacek Rumiński. Politechnika Gdańska, Inżynieria Biomedyczna

Wstęp do ruby dla programistów javy

Obszar statyczny dane dostępne w dowolnym momencie podczas pracy programu (wprowadzone słowem kluczowym static),

JAVA W SUPER EXPRESOWEJ PIGUŁCE

Laboratorium 03: Podstawowe konstrukcje w języku Java [2h]

Programowanie obiektowe

Polimorfizm. dr Jarosław Skaruz

Języki Programowania II Wykład 3. Java podstawy. Przypomnienie

Przygotował: Jacek Sroka. PO* - Scala (iteratory, leniwość, view bounds i konwersje)

Programowanie obiektowe

WYKORZYSTANIE JĘZYKA GROOVY W TESTACH JEDNOSTKOWYCH, INTEGRACYJNYCH I AUTOMATYCZNYCH. Mirosław Gołda, Programista Java

Kurs programowania. Wykład 2. Wojciech Macyna. 17 marca 2016

Programowanie obiektowe

Aplikacje Internetowe. Najprostsza aplikacja. Komponenty Javy. Podstawy języka Java

Java Język programowania

KOTLIN. Język programowania dla Androida

Programowanie RAD Delphi

Podstawowe elementy proceduralne w C++ Program i wyjście. Zmienne i arytmetyka. Wskaźniki i tablice. Testy i pętle. Funkcje.

Programowanie obiektowe

Co jeszcze mogą nam dać adnotacje? Adam Warski

Programowanie obiektowe

Polimorfizm, metody wirtualne i klasy abstrakcyjne

1 Atrybuty i metody klasowe

Tworzenie aplikacji w języku Java

1. Które składowe klasa posiada zawsze, niezależnie od tego czy je zdefiniujemy, czy nie?

Dawid Gierszewski Adam Hanasko

Programowanie w Javie - wykład 3

Podstawowe części projektu w Javie

Wykład 2 Wybrane konstrukcje obiektowych języków programowania (1)

Programowanie Komputerów

Obiekt klasy jest definiowany poprzez jej składniki. Składnikami są różne zmienne oraz funkcje. Składniki opisują rzeczywisty stan obiektu.

Dziedziczenie. dr Jarosław Skaruz

Język programowania Scala + aktorzy Akka

Laboratorium Programowania Kart Elektronicznych

Wątki. Definiowanie wątków jako klas potomnych Thread. Nadpisanie metody run().

Informatyka I. Klasy i obiekty. Podstawy programowania obiektowego. dr inż. Andrzej Czerepicki. Politechnika Warszawska Wydział Transportu 2018

Programowanie obiektowe

Programowanie obiektowe

Klasa jest nowym typem danych zdefiniowanym przez użytkownika. Najprostsza klasa jest po prostu strukturą, np

Współbieżność i równoległość w środowiskach obiektowych. Krzysztof Banaś Obliczenia równoległe 1

Wstęp do Programowania 2

Scala. Wprowadzenie do języka.

JAVA. Java jest wszechstronnym językiem programowania, zorientowanym. apletów oraz samodzielnych aplikacji.

Współbieżność w środowisku Java

Wprowadzenie do języka Java

DIAGRAMY SYNTAKTYCZNE JĘZYKA TURBO PASCAL 6.0

Programowanie w języku Java - Wyjątki, obsługa wyjątków, generowanie wyjątków

Java podstawy jęyka. Wykład 2. Klasy abstrakcyjne, Interfejsy, Klasy wewnętrzne, Anonimowe klasy wewnętrzne.

20. Pascal i łączenie podprogramów Pascala z programem napisanym w C

Laboratorium Programowania Kart Elektronicznych

Wykład 4: Klasy i Metody

Strona główna. Strona tytułowa. Programowanie. Spis treści. Sobera Jolanta Strona 1 z 26. Powrót. Full Screen. Zamknij.

Programowanie obiektowe

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)

dziedziczenie - po nazwie klasy wystąpią słowa: extends nazwa_superklasy

JAVA. Platforma JSE: Środowiska programistyczne dla języka Java. Wstęp do programowania w języku obiektowym. Opracował: Andrzej Nowak

Programowanie komputerowe. Zajęcia 7

METODY I JĘZYKI PROGRAMOWANIA PROGRAMOWANIE STRUKTURALNE. Wykład 02

Interfejsy. Programowanie obiektowe. Paweł Rogaliński Instytut Informatyki, Automatyki i Robotyki Politechniki Wrocławskiej

Konstruktory. Streszczenie Celem wykładu jest zaprezentowanie konstruktorów w Javie, syntaktyki oraz zalet ich stosowania. Czas wykładu 45 minut.

Programowanie obiektowe zastosowanie języka Java SE

Wstęp do programowania. Różne różności

Swift (pol. jerzyk) nowy język programowania zaprezentowany latem 2014 r. (prace od 2010 r.)


Programowanie w C++ Wykład 14. Katarzyna Grzelak. 3 czerwca K.Grzelak (Wykład 14) Programowanie w C++ 1 / 27

Dziedziczenie. Tomasz Borzyszkowski

Java. język programowania obiektowego. Programowanie w językach wysokiego poziomu. mgr inż. Anna Wawszczak

Polimorfizm a klasy generyczne w języku Java. Zdzisław Spławski 1

Programowanie w Javie - wykład 2

Wykład 6: Dziedziczenie

Enkapsulacja, dziedziczenie, polimorfizm

Kurs programowania. Wykład 13. Wojciech Macyna. 14 czerwiec 2017

Programowanie w środowiskach graficznych. Wykład 3 Język C#

Kurs programowania. Wykład 9. Wojciech Macyna. 28 kwiecień 2016

Technologie i usługi internetowe cz. 2

Programowanie strukturalne. Opis ogólny programu w Turbo Pascalu

Programowanie obiektowe

1. Wartość, jaką odczytuje się z obszaru przydzielonego obiektowi to: a) I - wartość b) definicja obiektu c) typ oboektu d) p - wartość

Podstawy programowania skrót z wykładów:

WSNHiD, Programowanie 2 Lab. 2 Język Java struktura programu, dziedziczenie, abstrakcja, polimorfizm, interfejsy

Podstawy programowania. Wykład Funkcje. Krzysztof Banaś Podstawy programowania 1

Programowanie obiektowe

Transkrypt:

1 Scala Wprowadzenie

2 Czemu Scala? Język wzorowany na Javie i Haskelu nowoczesny obiektowy język programowania jednocześnie język funkcyjny progr. obiektowe uzupełnia pozostałe paradygmaty (jest ortogonalne do nich) Programy uruchamiają się na JVM można swobodnie odwoływać się do istniejącego kodu i bibliotek Javy Silnie typowany ciekawy system typów Zwięzła składnia i silniejsza abstrakcja = prostsze programy = mniej błędów Zaprojektowany do wyrażania powszechnych wzorców projektowych Udogodnienia do programowania równoległego i rozproszonego Robi się trendy (Spark)?

3 Pierwszy przykład object HelloWorld { def main(args: Array[String]) { println("hello, world!") main() jest procedurą object deklaruje Singleton (klasa i egzemplarz) Nie ma potrzeby dla składowych statycznych

4 Jak uruchamiać - shell > scala This is a Scala shell. Type in expressions to have them evaluated. Type :help for more information. scala> object HelloWorld { def main(args: Array[String]) { println("hello, world!") defined module HelloWorld scala> HelloWorld.main(null) Hello, world! scala>:q

5 Jak uruchamiać - skrypt #!/bin/sh exec scala "$0" "$@"!# object HelloWorld { def main(args: Array[String]) { println("hello, world! " + args.tolist) HelloWorld.main(args) >./script.sh

6 Jak uruchamiać - skrypt #!/bin/sh exec scala "$0" "$@"!# args.foreach(println) >./script.sh #! shebang interpreter directive exec is used to run scala without creation new process. Commands which go right after exec will not be executed!# is simple marker for scala utility (see notes below)

7 #! /bin/sh echo Header exec echo!# echo Body $./test.sh Header -------------- ---------------- #! /bin/sh echo Header!# echo Body $./test.sh Header./test.sh: line 4:!#: command not found Body

8 exec scala -classpath "lib/lib.1.jar:lib/lib.2.jar" "$0" "$@" exec scala -savecompiled "$0" "$@" //i zaglądamy do jara o nazwie takiej jak skrypt

9 Jak uruchamiać - kompilacja Kompilacja do bytecodu Javy > scalac HelloWorld.scala lub > scalac -d dir_for_classes/jar HelloWorld.scala lub fsc szybki kompilator korzystający z demona Uruchamianie > scala HelloWorld lub > scala -classpath classes HelloWorld argumentem powinien być obiekt najwyższego poziomu jeżeli występuje klauzula extends Application to wykonywane są wszystkie polecenia object HelloWorld2 extends Application { println("hello, world!") wpp wykonywana jest metoda main

10 Prezentacja IDE i worksheetów

11 Wygodniejsze importy import java.util.{date, Locale import java.text.dateformat import java.text.dateformat._ Zwięzłe importowanie wielu klas z pakietu _ zamiast * object FrenchDate { def main(args: Array[String]) { val now = new Date val df = getdateinstance(long,locale.france) println(df format now) Zwykły import można użyć do importowania składowych zamiast static w Scali są obiekty (ale Javowe składowe statyczne też można importować) Dopuszczalna funkcyjna składnia wywoływania metod i przekazywania parametrów Domyślnie importowane są całe pakiety java.lang, scala (np. Int, Boolean) oraz składowe obiektu scala.predef (np. scala.predef.assert)

12 Wszystko jest obiektem Włącznie z liczbami i funkcjami 1 + 2 * 3 / x (1).+(((2).*(3))./(x)) 1.+(2) (1).+(2) //żeby lexer nie wybrał najdłuższego dopasowanie dla identyfikatorów

Funkcje też są obiektami object Timer { def oncepersecond(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 def timeflies() { println("time flies like an arrow...") def main(args: Array[String]) { oncepersecond(timeflies) object TimerAnonymous { def oncepersecond(callback: () => Unit) { while (true) { callback(); Thread sleep 1000 Możemy przekazywać funkcje jako parametry () => Unit to typ wszystkich funkcji bez argumentów i bez wartości zwrotnej Do wypisywanie użyliśmy predefiniowanej metody println() zamiast System.out (ze scala.predef) Często wygodnie jest używać funkcji anonimowych def main(args: Array[String]) { oncepersecond(() => println("time flies like an arrow...")) 13

14 Klasy class Complex(real: Double, imag: Double) { def re() = real def im() = imag object ComplexNumbers { def main(args: Array[String]) { val c = new Complex(1.2, 3.4) println("imaginary part: " + c.im()) class Complex(real: Double, imag: Double) { def re = real def im = imag val xyz = 5 override def tostring() = "" + re + (if (im < 0) "" else "+") + im + "i" Klasy w Scali mają parametry new Complex(1.5, 2.3) Typy zwrotne zazwyczaj mogą być wywnioskowane przez kompilator, ale są dobrą dokumentacją Metody bezparametrowe można zdefiniować jako f()=... oraz f= Ale pierwszą można wywoływać jako f() i f, a drugą tylko jako f Konwencja: jak są efekty uboczne to f()=..., jak nie ma to f= i wtedy może być bezpiecznie zamienione na val Domyślną nadklasą jest scala.anyref Przedefiniowując metody trzeba to jawnie wskazać

15 Warianty i dopasowywanie abstract class Tree case class Sum(l: Tree, r: Tree) extends Tree case class Var(n: String) extends Tree case class Const(v: Int) extends Tree //taką funkcją możemy //reprezentować środowisko //dla "x" zwraca 5 wpp wyjątek { case "x" => 5 //alias dla typu type Environment = String => Int Wsparcie do reprezentacji drzew, np. XML Przykład: kalkulator z sumowaniem, stałymi całkowitymi i zmiennymi Const(5) zamiast new Const(5) Automatycznie są gettery np. dla c egzemplarza Const mamy c.v equals i hashcode działają na strukturze tostring wypisuje "literał np. Sum(Var(x),Const(1)) Można dopasowywać do wzorca

Warianty i dopasowywanie c.d. def eval(t: Tree, env: Environment): Int = t match { case Sum(l, r) => eval(l, env) + eval(r, env) case Var(n) => env(n) case Const(v) => v //jak nic się nie dopasuje to wyjątek def derive(t: Tree, v: String): Tree = t match { case Sum(l, r) => Sum(derive(l, v), derive(r, v)) case Var(n) if (v == n) => Const(1) //dopasowanie warunkowe case _ => Const(0) //guard def main(args: Array[String]) { val exp: Tree = Sum(Sum(Var("x"),Var("x")),Sum(Const(7),Var("y"))) val env: Environment = { case "x" => 5 case "y" => 7 println("expression: " + exp) //Expression: Sum(Sum(Var(x),Var(x)),Sum(Const(7),Var(y))) println("evaluation with =5, y=7: " + eval(exp, env)) //Evaluation with x=5, y=7: 24 println("derivative relative to x: " + derive(exp, "x")) //...to x: Sum(Sum(Const(1),Const(1)),Sum(Const(0),Const(0))) println("derivative relative to y: " + derive(exp, "y")) //..to y: Sum(Sum(Const(0),Const(0)),Sum(Const(0),Const(1))) 16

17 Dopasowywanie wzorców vs polimorfizm Przy pomocy dopasowywania wzorców bardzo łatwo dodać nową metodę dla całej hierarchii. Dużo roboty jak nowy węzeł. Za pomocą polimorfizmu łatwo dodać nowy rodzaj węzła. Dużo roboty jak nowa metoda.

18 Traits trait Ord { def < (that: Any): Boolean def <=(that: Any): Boolean = (this < that) (this == that) def > (that: Any): Boolean =!(this <= that) def >=(that: Any): Boolean =!(this < that) Wzbogacanie klasy (interfejs z implementacją) Nie może mieć parametrów konstruktora Można wmieszać do obiektu wiele różnych implementacji Jak kilka razy ta sama metoda to wygrywa implementacja najbardziej na prawo (np. ciało klasy jest bardzo na prawo) Any to bardziej ogólny Object //przy deklaracji class CollegeStudent extends Student with Worker with Underpaid with Young //przy tworzeniu egzemplarza class CollegeStudent extends Student new CollegeStudent with Worker with Underpaid with NotSoYoungAnymore

Traits c.d. class Date(y: Int, m: Int, d: Int) extends Ord { def year = y; def month = m def day = d override def tostring(): String = year + "" + month + "" + day override def equals(that: Any): Boolean = that.isinstanceof[date] && { val o = that.asinstanceof[date] o.day == day && o.month == month && o.year == year //wynik ostatniej linijki jako return def <(that: Any): Boolean = { if (!that.isinstanceof[date]) sys.error("cannot compare " + that + " and a Date") //zgłasza RuntimeException //w Scali nie ma wyjątków kontrolowanych/nadzorowanych val o = that.asinstanceof[date] (year < o.year) (year == o.year && (month < o.month (month == o.month && day < o.day))) 19

20 Generyki class Reference[T] { private var contents: T = _ def set(value: T) { contents = value def get: T = contents Parametryzowanie kodu typami Piszemy ogólny kod i nie musimy bez przerwy rzutować "_ to wartość domyślna dla zmiennej object IntegerReference { def main(args: Array[String]) { val cell = new Reference[Int] cell.set(13) println("reference contains the half of " + (cell.get * 2))

Quicksort def sort(a: Array[Int]) { def swap(i: Int, j: Int) { val t = a(i); a(i) = a(j); a(j) = t def sort1(l: Int, r: Int) { val pivot = a((l + r) / 2) var i = l var j = r while (i <= j) { while (a(i) < pivot) i += 1 while (a(j) > pivot) j -= 1 if (i <= j) { swap(i, j) i += 1 j -= 1 if (l < j) sort1(l, j) if (j < r) sort1(i, r) deklaracje zaczynają się zarezerwowanym słowem: def, var, val typ podajemy po symbolu i : jak się da to kompilator domyśli się typu i nie trzeba go podawać Array[Int] zamiast Int[] a(i) zamiast a[i] zagnieżdżone funkcje mają dostęp do parametrów i zmiennych zagadka: gdzie jest błąd w kodzie? if (a.length > 1) sort1(0, a.length - 1) 21

22 Quicksort c.d. object sort { def sort(a: Array[Int]) { //... def println(ar: Array[Int]) { def print1 = { def iter(i: Int): String = ar(i) + (if (i < ar.length-1) "," + iter(i+1) else "") if (ar.length == 0) "" else iter(0) Console.println("[" + print1 + "]") def main(args: Array[String]) { val ar = Array(6, 2, 8, 5, 1) println(ar) sort(ar) println(ar)

Quicksort wersja funkcyjna def sort(a: Array[Int]): Array[Int] = { if (a.length < 2) a else { val pivot = a(a.length / 2) Array.concat(sort(a.filter(x => x < pivot)), a.filter(x => x == pivot), sort(a.filter(x => x > pivot))) Obiekty Array[T] mają metodę (pochodzącą z klasy Seq[T]) def filter(p: T -> Boolean): Array[T] Można użyć składni a.filter(_ < pivot) a nawet (partially applied function) a.filter(pivot >) Inny sposób zapisania tej funkcji to x => pivot > x Operatory przekładają się na wywołania metod: a filter (pivot >) Dla podstawowych operatorów kompilator powinien generować dobry kod Ponieważ ciało funkcji jest wyrażeniem można pominąć { 23

24 Dyskusja zapotrzebowanie na pamięć wielowątkowość

25 Ćwiczenie Jaki będzie wynik class Person(val name:string, var age:int) def person = new Person("Kumar",12) person.age = 20 println(person.age)

26 Funkcje wyższego rzędu def While (p: => Boolean) (s: => Unit) { if (p) {s; While(p)(s) tak naprawdę jest specjalna konstrukcja (a nie powyższa definicja) oba parametry są bezparametrowe specjalne znaczenie : => Unit to tak jakby void jak nie zwracamy żadnego wyniku to tak jak byśmy zwracali wartość unit () nie trzeba podawać return, domyślnie wynikiem funkcji jest wynik ostatniego wyrażenia

27 Wyrażenia scala> 87+145 res0: Int = 232 scala> 5+2*3 res1: Int = 11 scala> "hello"+" world!" res2: java.lang.string = hello world! scala> def pi = 3.141592 pi: Double scala> def radius = 10 radius: Int scala> 2*pi*radius res7: Double = 62.83184

28 Kiedy jest wyliczana wartość? wyrażenie w def x = e jest wyliczane dopiero jak jest potrzebne (przekazywane przez nazwę) wyrażenie w val x = e jest wyliczane w chwili deklaracji (przekazywane przez wartość) zazwyczaj wyrażenia wyliczane są od lewej (redukcja) (2*pi)*radius (2*3.141592)*radius 6.183184*radius 6.183184*10 61.83184

29 Proste funkcje scala> def square(x: Double) = x*x square: (Double)Double scala> square(2) res11: Double = 4.0 scala> square(5+3) res12: Double = 64.0 scala> square(square(4)) res13: Double = 256.0 scala> def sumofsquares(x: Double, y: Double) = square(x)+square(y) sumofsquares: (Double,Double)Double scala> sumofsquares(3,2+2) res14: Double = 25.0

30 Wyliczanie wartość funkcji call-by-value sumofsquares(3, 2+2) sumofsquares(3, 4) square(3)+square(4) 3*3+square(4) 9+square(4) 9+4*4 9+16 25 call-by-name sumofsquares(3, 2+2) square(3)+square(2+2) 3*3+square(2+2) 9+square(2+2) 9+(2+2)*(2+2) 9+4*4 9+16 25 Dla czystych funkcji zawsze ten sam wynik call-by-value nie powtarza wyliczania argumentów Zazwyczaj bardziej wydajny; domyślny (w Scali) call-by-name nie wylicza nieużywanych (niepotrzebnych) argumentów

31 Wyliczanie wartości funkcji c.d. call-by-value można zapętlić scala> def loop: Int = loop loop: Int scala> def first(x: Int, y: Int) = x first: (Int,Int)Int scala> first(1,loop) call-by-name można wymusić scala> def constone(x:int, y: => Int) = 1 constone: (Int,=> Int)Int scala> constone(1,loop) res2: Int = 1 scala> constone(loop,1)//pętla

32 def vs val scala> def x = loop x: Boolean scala> val x = loop //potrzebne Ctrl+c

33 If-else Jak w Javie, ale w Scali jest również wyrażeniem (jak Javowy operator ternarny...?... :...) scala> def abs(x: Double) = if (x >= 0) x else -x abs: (Double)Double Stałe logiczne i operatory są takie same jak w Javie (leniwie, czyli short circut ) Przez rozpisywanie:!true false!false true true && e e false && e false true e true false e e Ćwiczenie: zdefiniuj if-then-else przez rozpisywanie (dla true i false)

34 ćwiczenie Zdefiniuj bez używania && ani and(x, y) == x && y or(x, y) == x y

35 ćwiczenie Zdefiniuj bez używania && ani and(x, y) == x && y or(x, y) == x y def and(x:boolean,y: =>Boolean) = if(x) y else false def and(x:boolean,y: =>Boolean) = if(!x) false else y def or(x:boolean,y: =>Boolean) = if(x) true else y def or(x:boolean,y: =>Boolean) = if(!x) y else true

36 Metoda Newtona sqrt(x) to y taki że y*y=x, inaczej y=x/y znajdujemy kolejne przybliżenia i uśredniamy y x/y (y+x/y)/2 1 2/1 = 2 1.5 1.5 2/1.5 = 1.3333 1.4167 1.4167 2/1.4167 = 1.4118 1.4142 1.4142...... Inaczej: x_{n+1=x_n f(x_n)/f'(x_n) dla f(x)=x^2-s

37 Przykład rozwiązania def sqrt(x: Double) = sqrtiter(1.0, x) def sqrtiter(guess: Double, x: Double): Double = if (isgoodenough(guess, x)) guess else sqrtiter(improve(guess, x), x) def improve(guess: Double, x: Double) = (guess + x/guess)/2 def isgoodenough(guess: Double, x: Double) = abs(square(guess) x) < 0.001

38 Zagnieżdżanie funkcji pomocniczych def sqrt(x: Double) = { def sqrtiter(guess: Double, x: Double): Double = if (isgoodenough(guess, x)) guess else sqrtiter(improve(guess, x), x) def improve(guess: Double, x: Double) = (guess + x/guesss)/2 def isgoodenough(guess: Double, x: Double) = abs(square(guess) x) < 0.001 sqrtiter(1.0, x)

39 Standardowa widoczność w zagnieżdżonych blokach def sqrt(x: Double) = { def sqrtiter(guess: Double): Double = if (isgoodenough(guess, x)) guess else sqrtiter(improve(guess, x), x) def improve(guess: Double) = (guess + x/guesss)/2 def isgoodenough(guess: Double) = abs(square(guess) x) < 0.001 sqrtiter(1.0)

40 ; Każda definicja w bloku musi się kończyć ; Domyślny średnik jest dodawany na końcu każdej linii, chyba że: linia kończy się słowem lub operatorem infiksowym, które nie byłyby dozwolone na końcu wyrażenia następna linia zaczyna się słowem od którego nie mogłoby się zaczynać wyrażenie jesteśmy otoczeni nawiasami Przykłady poprawnego kodu: def f(x: Int) = x + 1; f(1)+f(2) def g(x: Int) = x + 1 g(1)+g(2) def h(x: Int) = {x+1; h(1)+h(2) //tu średnik jest obowiązkowy

41 przykłady c.d. def m(x: Int) = x + y m(1)*m(2) def n(x: Int) = ( x //przez nawiasy tu nie będzie średnika + y //i wyliczy się do x+y, a nie +y ) n(1)/n(2)

42 Rekursja ogonowa def gcd(a: Int, b: Int): Int = if (b == 0) a else gcd(b, a % b) gcd(14, 21) if (21 == 0) 14 else gcd(21, 14 % 21) if (false) 14 else gcd(21, 14 % 21) gcd(21, 14 % 21) gcd(21, 14) if (14 == 0) 21 else gcd(14, 21 % 14) gcd(14, 21 % 14) gcd(14, 7) if (7 == 0) 14 else gcd(7, 14 % 7) gcd(7, 14 % 7) gcd(7, 0) if (0 == 0) 7 else gcd(0, 7 % 0) 7

43 Rekursja ogonowa def factorial(n: Int): Int = if (n == 0) 1 else n * factorial(n-1) factorial(5) if (5 == 0) 1 else 5 * factorial(5-1) 5 * factorial(5-1) 5 * factorial(4) 5 * (4 * factorial(3)) 5 * (4 * (3 * factorial(2))) 5 * (4 * (3 * (2 * factorial(1)))) 5 * (4 * (3 * (2 * (1 * factorial(0)))) 5 * (4 * (3 * (2 * (1 * 1)))) 120 Tu i tak liczby całkowite nam się przekręcą, ale w wielu przypadkach warto się starać. Adnotacja @tailrec podobna do javowej @Override