Cyfroteka.pl

klikaj i czytaj online

Cyfro
Czytomierz
00357 006771 15380061 na godz. na dobę w sumie
Programowanie funkcyjne. Krok po kroku - ebook/pdf
Programowanie funkcyjne. Krok po kroku - ebook/pdf
Autor: Liczba stron: 160
Wydawca: Helion Język publikacji: polski
ISBN: 978-83-283-0246-4 Data wydania:
Lektor:
Kategoria: ebooki >> komputery i informatyka >> programowanie >> techniki programowania
Porównaj ceny (książka, ebook, audiobook).

Zmień swoje podejście do programowania!

Języki funkcyjne zdobywają wśród programistów coraz większą popularność. Jak bezboleśnie zmienić sposób myślenia na funkcyjny? Ułatwi Ci to niniejsza książka, w całości poświęcona temu podejściu do programowania.

Poznaj podstawy teoretyczne programowania funkcyjnego, a następnie zacznij zgłębiać tajniki typów funkcyjnych, rekurencji oraz zmiennych niepodlegających modyfikacji. Z kolejnych rozdziałów dowiedz się, czym są ewaluacja rygorystyczna i nierygorystyczna. Zobacz też, jak wykonać dopasowanie do wzorca. Co jeszcze znajdziesz w tej książce? Wprowadzenie do języka Scala, przedstawienie języka Groovy oraz opis technik funkcyjnego programowania obiektowego to tylko niektóre z poruszanych w niej tematów. Jeżeli chcesz zmienić sposób programowania na funkcyjny, to doskonała pozycja dla Ciebie!

Przekonaj się, jak podejście funkcyjne może ułatwić Ci życie!

Znajdź podobne książki Ostatnio czytane w tej kategorii

Darmowy fragment publikacji:

Tytuł oryginału: Becoming Functional Tłumaczenie: Lech Lachowski ISBN: 978-83-283-0243-3 © 2015 Helion S.A. Authorized Polish translation of the English edition of Becoming Functional, ISBN 9781449368173. © 2014 Joshua Backfield. This translation is published and sold by permission of O’Reilly Media, Inc., which owns or controls all rights to publish and sell the same. All rights reserved. No part of this book may be reproduced or transmitted in any form or by any means, electronic or mechanical, including photocopying, recording or by any information storage retrieval system, without permission from the Publisher. Wszelkie prawa zastrzeżone. Nieautoryzowane rozpowszechnianie całości lub fragmentu niniejszej publikacji w jakiejkolwiek postaci jest zabronione. Wykonywanie kopii metodą kserograficzną, fotograficzną, a także kopiowanie książki na nośniku filmowym, magnetycznym lub innym powoduje naruszenie praw autorskich niniejszej publikacji. Wszystkie znaki występujące w tekście są zastrzeżonymi znakami firmowymi bądź towarowymi ich właścicieli. Autor oraz Wydawnictwo HELION dołożyli wszelkich starań, by zawarte w tej książce informacje były kompletne i rzetelne. Nie biorą jednak żadnej odpowiedzialności ani za ich wykorzystanie, ani za związane z tym ewentualne naruszenie praw patentowych lub autorskich. Autor oraz Wydawnictwo HELION nie ponoszą również żadnej odpowiedzialności za ewentualne szkody wynikłe z wykorzystania informacji zawartych w książce. Wydawnictwo HELION ul. Kościuszki 1c, 44-100 GLIWICE tel. 32 231 22 19, 32 230 98 63 e-mail: helion@helion.pl WWW: http://helion.pl (księgarnia internetowa, katalog książek) Drogi Czytelniku! Jeżeli chcesz ocenić tę książkę, zajrzyj pod adres http://helion.pl/user/opinie/pfukpk Możesz tam wpisać swoje uwagi, spostrzeżenia, recenzję. Pliki z przykładami omawianymi w książce można znaleźć pod adresem: ftp://ftp.helion.pl/przyklady/pfukpk.zip Printed in Poland. • Kup książkę • Poleć książkę • Oceń książkę • Księgarnia internetowa • Lubię to! » Nasza społeczność Spis tre(cid:316)ci Przedmowa ......................................................................................7 Przegl(cid:241)d koncepcji programowania funkcyjnego 1. Wprowadzenie .............................................................................. 15 15 16 16 16 16 16 17 17 17 18 Typy funkcyjne Funkcje czyste Rekurencja Zmienne niemutowalne Ewaluacja nierygorystyczna Instrukcje Dopasowywanie do wzorca Programowanie funkcyjne i wspó(cid:228)bie(cid:276)no(cid:264)(cid:232) Podsumowanie 2. Typy funkcyjne ............................................................................... 19 19 22 22 Wprowadzenie do firmy XXY Funkcje jako obiekty Refaktoryzacja przy u(cid:276)yciu struktur if-else Refaktoryzacja przy u(cid:276)yciu obiektów funkcji do wyodr(cid:246)bniania pól Funkcje anonimowe Funkcje lambda Domkni(cid:246)cia Funkcje wy(cid:276)szego rz(cid:246)du Refaktoryzacja funkcji get za pomoc(cid:241) j(cid:246)zyka Groovy Podsumowanie 24 30 30 33 35 37 38 3 Kup książkęPoleć książkę 3. Funkcje czyste ................................................................................ 41 41 45 50 53 54 Dane wyj(cid:264)ciowe zale(cid:276)(cid:241) od danych wej(cid:264)ciowych Oczyszczanie funkcji Skutki uboczne Podsumowanie Przestawianie si(cid:246) na j(cid:246)zyk Groovy 4. Zmienne niemutowalne ................................................................59 59 65 71 Mutowalno(cid:264)(cid:232) Niemutowalno(cid:264)(cid:232) Podsumowanie 5. Rekurencja .....................................................................................73 74 77 80 Wprowadzenie do rekurencji Rekurencja Rekurencja ogonowa Refaktoryzacja funkcji countEnabledCustomersWithNoEnabledContacts Podsumowanie Wprowadzenie do j(cid:246)zyka Scala 81 83 84 6. Ewaluacje rygorystyczne i nierygorystyczne ...............................87 88 89 93 96 Ewaluacja rygorystyczna Ewaluacja nierygorystyczna (leniwa) Leniwo(cid:264)(cid:232) mo(cid:276)e stwarza(cid:232) problemy Podsumowanie 7. Instrukcje ........................................................................................99 100 Skok na g(cid:228)(cid:246)bok(cid:241) wod(cid:246) Proste instrukcje 100 102 Instrukcje blokowe 104 Wszystko jest instrukcj(cid:241) Podsumowanie 112 4 (cid:95) Spis tre(cid:316)ci Kup książkęPoleć książkę 8. Dopasowywanie do wzorca .........................................................113 113 115 118 120 122 124 Proste dopasowania Proste wzorce Wyodr(cid:246)bnianie listy Wyodr(cid:246)bnianie obiektów Konwersja na dopasowywanie do wzorca Podsumowanie 9. Funkcyjne programowanie obiektowe ....................................... 125 125 127 129 132 Hermetyzacja statyczna Obiekty jako kontenery Kod jako dane Podsumowanie Od imperatywno(cid:264)ci do funkcyjno(cid:264)ci 10. Podsumowanie ............................................................................ 134 134 135 135 Wprowadzenie funkcji wy(cid:276)szego rz(cid:246)du Konwersja istniej(cid:241)cych metod na funkcje czyste Konwersja p(cid:246)tli na metody rekurencyjne lub ogonoworekurencyjne Konwersja zmiennych mutowalnych na niemutowalne Co dalej? Nowe wzorce projektowe Przekazywanie komunikatów dla osi(cid:241)gni(cid:246)cia wspó(cid:228)bie(cid:276)no(cid:264)ci Wzorzec Opcja (rozszerzenie wzorca Pusty Obiekt) Czysto(cid:264)(cid:232) metody singletona z zachowaniem obiektowo(cid:264)ci Wszystko razem Podsumowanie 136 136 136 137 137 137 138 139 147 Skorowidz .................................................................................... 149 Spis tre(cid:316)ci (cid:95) 5 Kup książkęPoleć książkę 6 (cid:95) Spis tre(cid:316)ci Kup książkęPoleć książkę ROZDZIA(cid:292) 7. Instrukcje Kiedy my(cid:264)limy o instrukcji, mamy na my(cid:264)li co(cid:264) takiego jak Integer x = 1 lub val x = 1, gdzie ustawiana jest zmienna. Technicznie rzecz bior(cid:241)c, ewalu- acja tego wiersza nie daje (cid:276)adnej warto(cid:264)ci. Co jednak, je(cid:264)li mieliby(cid:264)my ju(cid:276) zdefiniowan(cid:241) zmienn(cid:241) i ustawialiby(cid:264)my j(cid:241) pó(cid:274)niej, na przyk(cid:228)ad za pomoc(cid:241) instrukcji x = 1? Niektórzy ju(cid:276) wiedz(cid:241), (cid:276)e w j(cid:246)zykach C i Java ta instrukcja rze- czywi(cid:264)cie zwraca warto(cid:264)(cid:232) 1, tak jak zosta(cid:228)o to przedstawione w listingu 7.1. Listing 7.1. Prosta instrukcja przypisania public class Test { public static void main(String[] args) { Integer x = 0; System.out.println( X wynosi + (x = 1).toString()); } } Instrukcje w programowaniu funkcyjnym wprowadzaj(cid:241) koncepcj(cid:246) polegaj(cid:241)c(cid:241) na tym, (cid:276)e ka(cid:276)dy wiersz kodu powinien mie(cid:232) warto(cid:264)(cid:232) zwracan(cid:241). J(cid:246)zyki imperatywne takie jak Java zawieraj(cid:241) koncepcj(cid:246) operatora trójargumen- towego (ang. ternary operator). Daje to struktur(cid:246) if-else, która przeprowadza ewaluacj(cid:246) do pewnej warto(cid:264)ci. W listingu 7.2 zosta(cid:228)o przedstawione proste u(cid:276)ycie operatora trójargumentowego. Listing 7.2. Prosta instrukcja trójargumentowa public class Test { public static void main(String[] args) { Integer x = 1; System.out.println( X wynosi: + ((x 0) ? dodatnie : ujemne )); } } 99 Kup książkęPoleć książkę Gdyby(cid:264)my mogli zrobi(cid:232) wi(cid:246)kszy u(cid:276)ytek z instrukcji, mogliby(cid:264)my zmniejszy(cid:232) liczb(cid:246) posiadanych zmiennych. Je(cid:264)li ograniczymy liczb(cid:246) zmiennych, to zredu- kujemy mo(cid:276)liwo(cid:264)ci ich mutowania, przez co zwi(cid:246)kszymy mo(cid:276)liwo(cid:264)(cid:232) wyko- nywania procesów wspó(cid:228)bie(cid:276)nych oraz osi(cid:241)gni(cid:246)cia wi(cid:246)kszej funkcyjno(cid:264)ci! Skok na g(cid:293)(cid:253)bok(cid:233) wod(cid:253) Twój szef jest bardzo zadowolony z Twoich dokona(cid:254) w XXY. Jest naprawd(cid:246) pod wra(cid:276)eniem programowania funkcyjnego i chce, aby(cid:264) dokona(cid:228) konwersji z j(cid:246)zyka cz(cid:246)(cid:264)ciowo funkcyjnego na j(cid:246)zyk w pe(cid:228)ni funkcyjny. Nie powinno to by(cid:232) trudne, poniewa(cid:276) przez kilka ostatnich rozdzia(cid:228)ów osi(cid:241)gn(cid:246)li(cid:264)my ju(cid:276) do(cid:264)(cid:232) du(cid:276)y stopie(cid:254) funkcyjno(cid:264)ci. Wybierzemy j(cid:246)zyk, który dzia(cid:228)a na maszynie wirtualnej Javy (ang. Java Virtual Machine — JVM), aby nie wprowadza(cid:232) nowych technologii, takich jak (cid:264)rodowisko uruchomieniowe LISP lub Erlang. Mogliby(cid:264)my równie(cid:276) wybra(cid:232) j(cid:246)zyki takie jak Clojure lub Erjang, ale dla celów tej ksi(cid:241)(cid:276)ki u(cid:276)yjemy j(cid:246)zyka Scala, który ma sk(cid:228)adni(cid:246) podobn(cid:241) jak Java i nie wymaga d(cid:228)ugiej nauki. Proste instrukcje Przepiszemy ka(cid:276)d(cid:241) z naszych klas, zacznijmy wi(cid:246)c od najprostszego pliku, czyli klasy Contact. Przypomnijmy istniej(cid:241)cy plik w listingu 7.3. Listing 7.3. Plik Contact.groovy public class Contact { public final Integer contact_id = 0; public final String firstName = ; public final String lastName = ; public final String email = ; public final Boolean enabled = true; public Contact(Integer contact_id, String firstName, String lastName, String email, Boolean enabled) { this.contact_id = contact_id; this.firstName = firstName; this.lastName = lastName; this.email = email; this.enabled = enabled; } 100 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę public static List Customer setNameAndEmailForContactAndCustomer( Integer customer_id, Integer contact_id, String name, String email) { Customer.updateContactForCustomerContact( customer_id, contact_id, { contact - new Contact( contact.contact_id, contact.firstName, name, email, contact.enabled ) } ) } public void sendEmail() { println( Wysy(cid:239)anie wiadomo(cid:258)ci e-mail ) } } Zrefaktoryzujemy ten kod na odpowiednik w j(cid:246)zyku Scala, tak jak zosta(cid:228)o to przedstawione w listingu 7.4. Zwró(cid:232) uwag(cid:246), (cid:276)e w kodzie w j(cid:246)zyku Scala definiujemy zmienne instancji w zestawie nawiasów obok nazwy klasy. Mamy równie(cid:276) obiekt i klas(cid:246). Statyczne metody i sk(cid:228)adowe znajduj(cid:241) si(cid:246) wewn(cid:241)trz definicji obiektu, a nie klasy. Typy definiowane s(cid:241) tak(cid:276)e raczej po niej, a nie przed ni(cid:241). Listing 7.4. Plik Contact.scala object Contact { def setNameAndEmailForContactAndCustomer( customer_id : Integer, contact_id : Integer, name : String, email : String) : List[Customer] = { Customer.updateContactForCustomerContact( customer_id, contact_id, { contact = new Contact( contact.contact_id, contact.firstName, name, email, contact.enabled ) } Proste instrukcje (cid:95) 101 Kup książkęPoleć książkę ) } } class Contact(val contact_id : Integer, val firstName : String, val lastName : String, val email : String, val enabled : Boolean) { def sendEmail() = { println( Wysy(cid:239)anie wiadomo(cid:258)ci e-mail ) } } Chocia(cid:276) dla czytelno(cid:264)ci w tej ksi(cid:241)(cid:276)ce dodawanych jest wiele wier- szy, w tym wierszy pustych i definicji metod podzielonych na kilka wierszy, liczba linii kodu spada z 19 do 9. Wynika to ze sposobu, w jaki w j(cid:246)zyku Java definiujemy sk(cid:228)adowe i ustawiamy je za pomoc(cid:241) konstruktora. Instrukcje blokowe Kolejn(cid:241) klas(cid:241), z któr(cid:241) si(cid:246) zmierzymy, jest Contract. Jest to nieco trudniejsze, poniewa(cid:276) u(cid:276)ywali(cid:264)my obiektu Javy Calendar, który nie jest konstruktem zbyt funkcyjnym. Rzu(cid:232)my okiem na oryginalny plik w listingu 7.5. Listing 7.5. Plik Contract.groovy import java.util.List; import java.util.Calendar; public class Contract { public final Calendar begin_date; public final Calendar end_date; public final Boolean enabled = true; public Contract(Calendar begin_date, Calendar end_date, Boolean enabled) { this.begin_date = begin_date; this.end_date = end_date; this.enabled = enabled; } public Contract(Calendar begin_date, Boolean enabled) { this.begin_date = begin_date; this.end_date = this.begin_date.getInstance(); this.end_date.setTimeInMillis(this.begin_date.getTimeInMillis()); this.end_date.add(Calendar.YEAR, 2); this.enabled = enabled; } 102 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę public static List Customer setContractForCustomerList( List Integer ids, Boolean status) { Customer.updateContractForCustomerList(ids) { contract - new Contract(contract.begin_date, contract.end_date, status) } } } Przejd(cid:274)my dalej i przekonwertujmy t(cid:246) klas(cid:246), tak jak zosta(cid:228)o to przedstawione w listingu 7.6. Spójrzmy najpierw na fragment List[Integer], który przed- stawia sposób oznaczania typizowania uogólnionego w Scali. Widzimy rów- nie(cid:276) bardzo interesuj(cid:241)c(cid:241) sk(cid:228)adni(cid:246) def this(begin_date : Calendar, enabled : (cid:180)Boolean), za pomoc(cid:241) której definiujemy konstruktor alternacyjny. Istnieje tak(cid:276)e wiersz, który zawiera tylko warto(cid:264)(cid:232) c. To poprawne, gdy(cid:276) wiersz ten traktowany jest jako instrukcja, czyli uznawany jest nast(cid:246)pnie za warto(cid:264)(cid:232) zwracan(cid:241) tego bloku kodu. Listing 7.6. Plik Contract.scala import java.util.Calendar object Contract { def setContractForCustomerList(ids : List[Integer], status : Boolean) : List[Customer] = { Customer.updateContractForCustomerList(ids, { contract = new Contract(contract.begin_date, contract.end_date, status) }) } } class Contract(val begin_date : Calendar, val end_date : Calendar, val enabled : Boolean) { def this(begin_date : Calendar, enabled : Boolean) = this(begin_date, { val c = Calendar.getInstance() c.setTimeInMillis(begin_date.getTimeInMillis) c.add(Calendar.YEAR, 2) c }, enabled) } Najbardziej interesuj(cid:241)ce w tej sk(cid:228)adni jest wywo(cid:228)anie s(cid:228)owa kluczowego this, w którym przekazujemy to, co zdaje si(cid:246) by(cid:232) funkcj(cid:241), tam, gdzie przeka- zywana powinna by(cid:232) zmienna end_date. Dlaczego kompilator nie narzeka, (cid:276)e oczekiwana jest instancja Calendar, a nie metoda, która zwraca instancj(cid:246) Calendar? Kompilator inferuje, (cid:276)e nie przekazujesz metody, ale zamiast tego chcesz prze- prowadzi(cid:232) ewaluacj(cid:246) nawiasów {...}. Dlatego gdy wywo(cid:228)any jest konstruktor Instrukcje blokowe (cid:95) 103 Kup książkęPoleć książkę alternacyjny, wywo(cid:228)ujemy rzeczywisty konstruktor, a ewaluacja nawiasów {...} daje nam end_date typu Calendar. Konstruktory alternacyjne dzia(cid:228)aj(cid:241) w podobny sposób, w jaki Java pozwala przeci(cid:241)(cid:276)a(cid:232) konstruktory, aby przyjmowa(cid:228)y ró(cid:276)ne argumenty. Blok kodu przedstawiony w listingu 7.7 jest bardzo prosty. Tworzy obiekt Calendar, ustawiaj(cid:241)c czas w milisekundach na podstawie obiektu begin_date (przypomina to domkni(cid:246)cie). Nast(cid:246)pnie do daty dodawane s(cid:241) dwa lata, aby utworzy(cid:232) dat(cid:246) dwa lata pó(cid:274)niejsz(cid:241) wobec momentu zawarcia kontraktu. Na koniec zwracany jest nowo utworzony obiekt c, zawieraj(cid:241)cy dat(cid:246) dwa lata pó(cid:274)niejsz(cid:241) od daty pocz(cid:241)tkowej begin_date. Listing 7.7. Blok kodu okre(cid:264)laj(cid:241)cy warto(cid:264)(cid:232) dla end_date { val c = Calendar.getInstance() c.setTimeInMillis(begin_date.getTimeInMillis) c.add(Calendar.YEAR, 2) c } Ta instrukcja pozwala nam wyj(cid:264)(cid:232) poza standardowy paradygmat funkcyjny, w którym ka(cid:276)da linia kodu powinna by(cid:232) instrukcj(cid:241) mo(cid:276)liw(cid:241) do bezpo(cid:264)red- niego przekazania do innej funkcji lub u(cid:276)ycia. Mo(cid:276)na traktowa(cid:232) to jako instrukcj(cid:246) z(cid:228)o(cid:276)on(cid:241): mamy kilka instrukcji, które musz(cid:241) by(cid:232) poddane ewalu- acji, aby uzyska(cid:232) faktycznie wykorzystywan(cid:241) instrukcj(cid:246) ogóln(cid:241). Ten blok kodu jest interesuj(cid:241)cy, poniewa(cid:276) pokazuje, (cid:276)e ca(cid:228)kiem dos(cid:228)ownie wszystko jest instrukcj(cid:241). Ostatni wiersz (c) jest instrukcj(cid:241), gdy(cid:276) zwraca zmienn(cid:241) c. Tak(cid:276)e ca(cid:228)y blok kodu jest sam w sobie instrukcj(cid:241): po poddaniu ewaluacji wykonuje linie kodu w sekwencji i zwraca now(cid:241) warto(cid:264)(cid:232) c, któr(cid:241) zdefiniowali(cid:264)my. Wszystko jest instrukcj(cid:233) W ko(cid:254)cu zamierzamy przekonwertowa(cid:232) klas(cid:246) Customer, co nie powinno by(cid:232) zbyt trudne. Spójrzmy na oryginalny plik Groovy przedstawiony w lis- tingu 7.8. Listing 7.8. Plik Customer.groovy import java.util.ArrayList; import java.util.List; import java.util.Calendar; 104 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę public class Customer { static public List Customer allCustomers = new ArrayList Customer (); public final Integer id = 0; public final String name = ; public final String state = ; public final String domain = ; public final Boolean enabled = true; public final Contract contract = null; public final List Contact contacts = new ArrayList Contact (); @Lazy public List Contact enabledContacts = contacts.findAll { contact - contact.enabled } public Customer(Integer id, String name, String state, String domain, Boolean enabled, Contract contract, List Contact contacts) { this.id = id; this.name = name; this.state = state; this.domain = domain; this.enabled = enabled; this.contract = contract; this.contacts = contacts; } static def EnabledCustomer = { customer - customer.enabled == true } static def DisabledCustomer = { customer - customer.enabled == false } public static List String getDisabledCustomerNames() { Customer.allCustomers.findAll(DisabledCustomer).collect({customer - customer.name }) } public static List String getEnabledCustomerStates() { Customer.allCustomers.findAll(EnabledCustomer).collect({customer - customer.state }) } public static List String getEnabledCustomerDomains() { Customer.allCustomers.findAll(EnabledCustomer).collect({customer - customer.domain }) } public static List String getEnabledCustomerSomeoneEmail(String someone) { Customer.allCustomers.findAll(EnabledCustomer).collect({customer - Wszystko jest instrukcj(cid:233) (cid:95) 105 Kup książkęPoleć książkę someone + @ + customer.domain }) } public static ArrayList Customer getCustomerById( ArrayList Customer inList, final Integer id) { inList.findAll({customer - customer.id == id }) } public static void eachEnabledContact(Closure cls) { Customer.allCustomers.findAll { customer - customer.enabled customer.contract.enabled }.each { customer - customer.contacts.each(cls) } } public static List Customer updateCustomerByIdList( List Customer initialIds, List Integer ids, Closure cls) { if(ids.size() = 0) { initialIds } else if(initialIds.size() = 0) { [] } else { def idx = ids.indexOf(initialIds[0].id) def cust = idx = 0 ? cls(initialIds[0]) : initialIds[0] [cust] + updateCustomerByIdList( initialIds.drop(1), idx = 0 ? ids.minus(initialIds[0].id) : ids, cls ) } } public static List Customer updateContactForCustomerContact( Integer id, Integer contact_id, Closure cls) { updateCustomerByIdList(Customer.allCustomers, [id], { customer - new Customer( customer.id, customer.name, customer.state, customer.domain, customer.enabled, customer.contract, customer.contacts.collect { contact - if(contact.contact_id == contact_id) { cls(contact) } else { 106 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę contact } } ) }) } public static List Customer updateContractForCustomerList( List Integer ids, Closure cls) { updateCustomerByIdList(Customer.allCustomers, ids, { customer - new Customer( customer.id, customer.name, customer.state, customer.domain, customer.enabled, cls(customer.contract), customer.contacts ) }) } public static def countEnabledCustomersWithNoEnabledContacts = { List Customer customers, Integer sum - if(customers.isEmpty()) { return sum } else { int addition = (customers.head().enabled (customers.head().contacts.find({ contact - contact.enabled }) == null)) ? 1 : 0 return countEnabledCustomersWithNoEnabledContacts.trampoline( customers.tail(), addition + sum ) } }.trampoline() } Kiedy konwertujemy t(cid:246) klas(cid:246) i obiekt na j(cid:246)zyk Scala (patrz: listing 7.9), jedna rzecz nie dzia(cid:228)a: nie ma operatora trójargumentowego! Przypomnij sobie konstrukcj(cid:246) (warunek) ? true : false ?. Jak wida(cid:232) w pliku Scali, zast(cid:241)pili(cid:264)my j(cid:241) prawdziw(cid:241) instrukcj(cid:241) if. Listing 7.9. Plik Customer.scala object Customer { val allCustomers = List[Customer]() def EnabledCustomer(customer : Customer) : Boolean = customer.enabled == true Wszystko jest instrukcj(cid:233) (cid:95) 107 Kup książkęPoleć książkę def DisabledCustomer(customer : Customer) : Boolean = customer.enabled == (cid:180)false def getDisabledCustomerNames() : List[String] = { Customer.allCustomers.filter(DisabledCustomer).map({ customer = customer.name }) } def getEnabledCustomerStates() : List[String] = { Customer.allCustomers.filter(EnabledCustomer).map({ customer = customer.state }) } def getEnabledCustomerDomains() : List[String] = { Customer.allCustomers.filter(EnabledCustomer).map({ customer = customer.domain }) } def getEnabledCustomerSomeoneEmail(someone : String) : List[String] = { Customer.allCustomers.filter(EnabledCustomer).map({ customer = someone + @ + customer.domain }) } def getCustomerById(inList : List[Customer], customer_id : Integer) : List[Customer] = { inList.filter(customer = customer.customer_id == customer_id) } def eachEnabledContact(cls : Contact = Unit) { Customer.allCustomers.filter({ customer = customer.enabled customer.contract.enabled }).foreach({ customer = customer.contacts.foreach(cls) }) } def updateCustomerByIdList(initialIds : List[Customer], ids : List[Integer], cls : Customer = Customer) : List[Customer] = { if(ids.size = 0) { initialIds } else if(initialIds.size = 0) { List() } else { val precust = initialIds.find(cust = cust.customer_id == ids(0)) val cust = if(precust.isEmpty) { List() } else { List(cls(precust.get)) } cust ::: updateCustomerByIdList( initialIds.filter(cust = cust.customer_id == ids(0)), ids.drop(1), 108 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę cls ) } } def updateContactForCustomerContact(customer_id : Integer, contact_id : Integer, cls : Contact = Contact) : (cid:180)List[Customer] = { updateCustomerByIdList(Customer.allCustomers, List(customer_id), { customer = new Customer( customer.customer_id, customer.name, customer.state, customer.domain, customer.enabled, customer.contract, customer.contacts.map { contact = if(contact.contact_id == contact_id) { cls(contact) } else { contact } } ) }) } def updateContractForCustomerList(ids : List[Integer], cls : Contract = Contract) : (cid:180)List[Customer] = { updateCustomerByIdList(Customer.allCustomers, ids, { customer = new Customer( customer.customer_id, customer.name, customer.state, customer.domain, customer.enabled, cls(customer.contract), customer.contacts ) }) } def countEnabledCustomersWithNoEnabledContacts(customers : List[Customer], sum : Int) : Integer = { if(customers.isEmpty) { sum } else { val addition = if(customers.head.enabled customers.head.contacts.exists({ contact = contact.enabled })) { Wszystko jest instrukcj(cid:233) (cid:95) 109 Kup książkęPoleć książkę 1 } else { 0 } countEnabledCustomersWithNoEnabledContacts(customers.tail, addition + sum) } } } class Customer(val customer_id : Integer, val name : String, val state : String, val domain : String, val enabled : Boolean, val contract : Contract, val contacts : List[Contact]) { } Scala nie zawiera koncepcji trójargumentowych, poniewa(cid:276) wszystko jest ju(cid:276) instrukcj(cid:241). Oznacza to, (cid:276)e ewaluacja instrukcji if da jak(cid:241)(cid:264) warto(cid:264)(cid:232). Mo(cid:276)emy napisa(cid:232) if(warunek) { true } else { false }, a ewaluacja instrukcji if da nam warto(cid:264)(cid:232) true lub false. Spójrzmy teraz na kod w listingu 7.10, który przedstawia sposób, w jaki mo(cid:276)emy ustawi(cid:232) zmienn(cid:241) na podstawie instrukcji if. Listing 7.10. Zwrócony rezultat instrukcji if val addition = if(customers.head.enabled customers.head.contacts.exists({ contact = contact.enabled })) { 1 } else { 0 } Jak wida(cid:232), zmienna addition otrzyma warto(cid:264)(cid:232) 1 lub 0 w zale(cid:276)no(cid:264)ci od ewalu- acji instrukcji if. Dlaczego jest to o wiele bardziej interesuj(cid:241)ce ni(cid:276) operator trójargumentowy? Dlatego, (cid:276)e w tym przypadku if dzia(cid:228)a jak normalna instrukcja if, co oznacza, i(cid:276) mo(cid:276)na doda(cid:232) dowoln(cid:241) ilo(cid:264)(cid:232) kodu wewn(cid:241)trz sekcji true lub false instrukcji if. Operator trójargumentowy tak naprawd(cid:246) dopuszcza stosowanie tylko bardzo prostych wyra(cid:276)e(cid:254), takich jak warto(cid:264)(cid:232) lub podstawowe wywo(cid:228)anie metody. Co jednak tak naprawd(cid:246) znaczy stwierdzenie „wszystko jest instrukcj(cid:241)”? Oznacza to, (cid:276)e wszystko powinno ewaluowa(cid:232) do jakiej(cid:264) warto(cid:264)ci. Ale co to dok(cid:228)adnie znaczy? Wielu z nas zna standardow(cid:241) metodologi(cid:246) ziarna (ang. bean) w j(cid:246)zyku Java, która polega na posiadaniu zmiennej sk(cid:228)adowej z meto- dami zwracaj(cid:241)cymi i ustawiaj(cid:241)cymi. Oczywi(cid:264)cie metoda zwracaj(cid:241)ca zwraca jak(cid:241)(cid:264) warto(cid:264)(cid:232), ale co z metod(cid:241) ustawiaj(cid:241)c(cid:241)? Rzu(cid:232)my okiem na listing 7.11. 110 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę Listing 7.11. Metoda ustawiaj(cid:241)ca dla pola Foo w klasie Bar, która zwraca sam obiekt public class Bar { public Bar setFoo(Foo foo) { this.foo = foo; return this; } public Foo getFoo() { return this.foo; } } Umo(cid:276)liwia to (cid:228)a(cid:254)cuchowanie wywo(cid:228)a(cid:254) funkcji i ustawianie kilku sk(cid:228)ado- wych w jednym wierszu, tak jak zosta(cid:228)o to przedstawione w listingu 7.12. Ale dlaczego chcemy to zrobi(cid:232)? Po prostu w ten sposób mo(cid:276)emy przedefi- niowa(cid:232) metody ustawiaj(cid:241)ce i utworzy(cid:232) zmienne niemutowalne. Dlaczego? Poniewa(cid:276) wewn(cid:241)trz metod ustawiaj(cid:241)cych mo(cid:276)emy utworzy(cid:232) now(cid:241) instancj(cid:246) Bar z now(cid:241) warto(cid:264)ci(cid:241) i zwróci(cid:232) j(cid:241)! Oznacza to, (cid:276)e implementacja zmiennych niemutowalnych staje si(cid:246) prostsza. Listing 7.12. Metoda (cid:228)a(cid:254)cuchowania w obiekcie Bar return bar.setFoo(newFoo).setBaz(newBaz).setQux(newQux); A co z elementami takimi jak p(cid:246)tle for — czy to te(cid:276) s(cid:241) instrukcje? W(cid:228)a(cid:264)ciwie tak, ale nie w taki sposób jak mo(cid:276)na sobie wyobra(cid:276)a(cid:232). P(cid:246)tle for przyjmuj(cid:241) na ogó(cid:228) dwie postacie: normalnej p(cid:246)tli i wyra(cid:276)enia (ang. comprehension). Pierwszy typ p(cid:246)tli zosta(cid:228) przedstawiony w listingu 7.13. Listing 7.13. Przyk(cid:228)ad podstawowej p(cid:246)tli for w j(cid:246)zyku Scala val x = for(i - 0 until 10) { println(i) } Uruchomienie tego kodu powoduje wy(cid:264)wietlenie na ekranie liczb od 0 do 9. Co wa(cid:276)niejsze, dla zmiennej x ustawiana jest jaka(cid:264) warto(cid:264)(cid:232) — w tym przy- padku jest to warto(cid:264)(cid:232) Unit. Mo(cid:276)e si(cid:246) to wydawa(cid:232) dziwne, ale w j(cid:246)zyku Scala Unit jest w(cid:228)a(cid:264)ciwie typem void (czyli nie ma faktycznego typu). Oznacza to, (cid:276)e ewaluacja naszej p(cid:246)tli for w rzeczywisto(cid:264)ci nie zwróci(cid:228)a (cid:276)adnej warto(cid:264)ci. Czym wi(cid:246)c s(cid:241) wyra(cid:276)enia? Przyjrzyjmy si(cid:246) wyra(cid:276)eniu for w listingu 7.14. Listing 7.14. Podstawowe wyra(cid:276)enie for w j(cid:246)zyku Scala val x = for(i - 0 until 10) yield { i*2 } Wszystko jest instrukcj(cid:233) (cid:95) 111 Kup książkęPoleć książkę Mamy zmienn(cid:241) x, która jest list(cid:241) parzystych liczb z zakresu od 0 do 18. Wyra(cid:276)enie pozwala nam wygenerowa(cid:232) now(cid:241) list(cid:246) jakich(cid:264) elementów lub czasem iterowa(cid:232) przez inn(cid:241) list(cid:246). Spójrzmy na listing 7.15, w którym fak- tycznie przeprowadzamy iteracj(cid:246) przez inn(cid:241) list(cid:246). Listing 7.15. Wyra(cid:276)enie for dla innej listy w j(cid:246)zyku Scala val x = for(i - List(1,2,3,4)) yield { i*2 } Jaka jest wi(cid:246)c ró(cid:276)nica mi(cid:246)dzy tym a wykorzystaniem dla listy funkcji map? Przyjrzyjmy si(cid:246) listingowi 7.16. Ta funkcjonalno(cid:264)(cid:232) jest taka sama jak wyra- (cid:276)enie for przedstawione w listingu 7.15. Listing 7.16. Wywo(cid:228)anie map dla listy w j(cid:246)zyku Scala val x = List(1,2,3,4).map({ i = i*2 }) W takim razie kiedy nale(cid:276)y u(cid:276)y(cid:232) funkcji map, a kiedy wyra(cid:276)enia? Zasadniczo funkcja map jest dobra, je(cid:264)li masz ju(cid:276) list(cid:246) i musisz przeprowadzi(cid:232) na niej operacj(cid:246). Wyra(cid:276)enia for sprawdzaj(cid:241) si(cid:246), je(cid:264)li budujemy list(cid:246) lub chcemy prze- prowadzi(cid:232) okre(cid:264)lon(cid:241) operacj(cid:246) n razy. Podsumowanie Po(cid:264)wi(cid:246)cili(cid:264)my nieco czasu na przeprowadzenie migracji z j(cid:246)zyka Java do j(cid:246)zyka Scala, podkre(cid:264)laj(cid:241)c nasze przej(cid:264)cie na j(cid:246)zyk funkcyjny, z którego b(cid:246)dziemy mogli korzysta(cid:232) w kolejnych rozdzia(cid:228)ach. Instrukcje pozwalaj(cid:241) zredukowa(cid:232) niektóre podstawowe fragmenty kodu, a czasem s(cid:241) konieczne, aby nadal korzysta(cid:232) z okre(cid:264)lonych paradygmatów ziarna Javy. Na przyk(cid:228)a- dach takich jak obiekt Calendar zobaczyli(cid:264)my, (cid:276)e gdy musimy u(cid:276)y(cid:232) metod ustawiaj(cid:241)cych, mo(cid:276)emy utworzy(cid:232) instrukcje bloku, aby skonfigurowa(cid:232) obiekt Calendar. Instrukcje pokazuj(cid:241) nam równie(cid:276), (cid:276)e ka(cid:276)da metoda (nawet metody usta- wiaj(cid:241)ce) powinna mie(cid:232) jak(cid:241)(cid:264) form(cid:246) warto(cid:264)ci zwracanej. Je(cid:264)li mamy metody ustawiaj(cid:241)ce, które s(cid:241) instrukcjami, mo(cid:276)emy (cid:228)atwiej implementowa(cid:232) zmienne niemutowalne. Dzi(cid:246)ki instrukcjom nasz kod jest te(cid:276) bardziej zwi(cid:246)z(cid:228)y, ponie- wa(cid:276) zmuszaj(cid:241) nas one do zastanowienia si(cid:246), dlaczego piszemy konkretny wiersz kodu i co powinien on reprezentowa(cid:232) po ewaluacji. W ten sposób mo(cid:276)emy lepiej zrozumie(cid:232), dlaczego wiersz kodu dzia(cid:228)a tak, a nie inaczej. 112 (cid:95) Rozdzia(cid:293) 7. Instrukcje Kup książkęPoleć książkę Skorowidz A adnotacja @Lazy, 90, 92, 94 B baza danych, 65, 139 bean, Patrz: ziarno bezpiecze(cid:254)stwo w(cid:241)tków, 92 C closure, Patrz: domkni(cid:246)cie D domkni(cid:246)cie, 30, 32, 33, 35, 42, 62 Don’t Repeat Yourself, Patrz: zasada DRY E efekt uboczny, 41 ekspresyjno(cid:264)(cid:232), 135 ekstraktor, 118 Erjang, 100 ewaluacja leniwa, Patrz: ewaluacja nierygorystyczna nierygorystyczna, 15, 16, 87, 88, 89 rygorystyczna, 87, 88 statyczna, 89 F first-class function, Patrz: typ funkcyjny funkcja, 8 anonimowa, 30 czysta, 15, 16, 41, 45, 135 ekspresyjna, 135 filter, 44 findAll, 48 getCustomerById, 45 hermetyzacja, 24, 27 jako obiekt, 21, 22 lambda, 30 lista parametrów, 22, 30 (cid:228)a(cid:254)cuchowanie wywo(cid:228)a(cid:254), 111, 131 nazwa, 22, 30 nienazwana, 30 println, 16 przekazywanie do funkcji, 25, 27 rekurencyjna, Patrz: rekurencja warto(cid:264)(cid:232) zwracana, 22, 30 wy(cid:276)szego rz(cid:246)du, 135 G generic typing, Patrz: typizowanie uogólnione Groovy, 19, 37, 48, 74, 80, 90, 92, 135 sk(cid:228)adnia, 38 guard, Patrz: stra(cid:276)nik H hermetyzacja, 17 statyczna, 125 Hibernate, 97 149 Kup książkęPoleć książkę niemutowalna, 65 ogon, 75, 118 pusta, 48 roz(cid:228)o(cid:276)ona, 118 M makro, 22 mapowanie obiektowo- -relacyjne, Patrz: ORM maszyna wirtualna Javy, Patrz: JVM metoda singletona, 137, 138 statyczna, 101, 139 ustawiaj(cid:241)ca, 66 N niemutowalno(cid:264)(cid:232), 65, 76, 88 niewa(cid:276)no(cid:264)(cid:232), 43 nonstrict evaluation, Patrz: ewaluacja nierygorystyczna notacja tablicowa, 8 Null Object, Patrz: wzorzec projektowy Pusty Obiekt nullity, Patrz: niewa(cid:276)no(cid:264)(cid:232) O obiekt, 125 jako kontener, 127 object-oriented programming, Patrz: OOP OOP, 125, 138 operator ::, 118 sigma, 9 trójargumentowy, 79, 85, 99, 107, 110 ORM, 97 P pattern matching, Patrz: wzorzec dopasowywanie programowanie funkcyjne, 10, 15, 100, 104, 134 imperatywne, 9 obiektowe, 10, Patrz: OOP przetwarzanie równoleg(cid:228)e, 17 przypadek ko(cid:254)cowy, 73, 75, 82 pure function, Patrz: funkcja czysta R rachunek lambda, 25, 30 recursion, Patrz: rekurencja refaktoryzacja Groovy, 37 if-else, 22 obiekt funkcji do wyodr(cid:246)bniania pól, 24 rekurencja, 15, 16, 73, 74, 77, 78, 81, 137 ogonowa, 80, 136 Scala, 84 I immutable variable, Patrz: zmienna niemutowalna instrukcja, 16, 17, 99, 104, 110 blokowa, 102 ewaluacja, 8 if, 8, 114 konwersja na dopasowywanie do wzorca, 116, 122 match, 114 interfejs Runnable, 24 J Java ziarno, Patrz: ziarno j(cid:246)zyk Clojure, Patrz: Clojure Erjang, Patrz: Erjang Groovy, Patrz: Groovy Scala, Patrz: Scala JVM, 100 K komunikat, 17, 137 konstruktor, 104 krotka, 115, 117 L LISP, 100 lista g(cid:228)owa, 75, 118 mapowanie, 67 150 (cid:95) Skorowidz Kup książkęPoleć książkę S Scala, 19, 84, 100, 135, 139 sk(cid:228)adnia, 85 setter, Patrz: metoda ustawiaj(cid:241)ca side effects, Patrz: skutki uboczne skutki uboczne, 16, 50, 53 implementacja, 50 s(cid:228)owo kluczowe case, 114 match, 114 this, 103 volatile, 92 statement, Patrz: instrukcja static evaluation, Patrz: ewaluacja statyczna stos, 74, 79 stra(cid:276)nik, 124 sumowanie, Patrz: operator sigma symbol zast(cid:246)pczy, 65 T tail recursion, Patrz: rekurencja ogonowa ternary operator, Patrz: operator trójargumentowy trampolina, 80 transakcja bazy danych, 65 tuple, Patrz: krotka typ bezpiecze(cid:254)stwo, 24 funkcyjny, 15, 16, 19, 22 zwracany, 27 typizowanie uogólnione, 26, 27 W warto(cid:264)(cid:232) null, 48, 77, 137 w(cid:241)tek, 137 bezpiecze(cid:254)stwo, 92 pula, 137 wiersz polece(cid:254), 129 wspó(cid:228)bie(cid:276)no(cid:264)(cid:232), 17, 100, 137 wyj(cid:241)tek, 24 wyra(cid:276)enie regularne, 113 wzorzec, 114, 121 dopasowywanie, 16, 17, 113, 118, 119, 120, 128 warunek, 124 oparty na obiektach, 118 projektowy, 137 Opcja, 137, 138 Pusty Obiekt, 138 projektowy Strategia, 130 prosty, 115 Z zasada DRY, 21, 35, 36 ziarno, 110 zmienna domkni(cid:246)ta, 34 globalna, 16 instancji, 101 leniwa, 87, 89, 90, 93 mutowalna, 60, 87, 136 niemutowalna, 15, 16, 59, 65, 66, 88, 125, 136 znak ::, 118 , 114 _, 114 = , 124 (cid:228)a(cid:254)cuch, 114 Skorowidz (cid:95) 151 Kup książkęPoleć książkę Kup książkęPoleć książkę
Pobierz darmowy fragment (pdf)

Gdzie kupić całą publikację:

Programowanie funkcyjne. Krok po kroku
Autor:

Opinie na temat publikacji:


Inne popularne pozycje z tej kategorii:


Czytaj również:


Prowadzisz stronę lub blog? Wstaw link do fragmentu tej książki i współpracuj z Cyfroteką: