Lambdas (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017
Funktioner En funktion (i programmeringstermer) är en operation som tar ett eller flera argument, och ger ett resultat. Quiz: Vad skiljer en funktion från en metod? En statisk metod i Java är en funktion. Vi kallar den bara något annat. En instansmetod i Java är också en funktion, med särskild syntax, där instansen på vilken metoden anropas är ett implicit argument till funktionen. Ibland används distinktionen att en funktion ska vara deterministisk, eller till och med pure, men oftast inte.
Funktionella språk Ett programspråk sägs vara funktionellt om det tillåter oss att använda funktioner som om de vore värden ( first-class functions ): Deklarera variabler som representerar funktioner: f = show Applicera funktionsvariabler på argument:. x = f 5 Skicka funktioner som argument till andra funktioner (metoder). map f [1,2,3,4,5] Skapa anonyma funktioner som värden: map (\x -> x+5) [1,2,3,4,5] Exemplen givna med Haskell-syntax
Lambda expression Termen lambda expression ( lambda-uttryck ) beskriver just en funktion som används anonymt. Ursprunget är Alonzo Church s Lambda calculus. (\x -> x+5) = λx.x+5 Ta ett argument, som vi kallar x, och gör så här
Lambdas och Java Så sent som i Java 8 (2014) har vi fått stöd för lambda expressions i Java. Vad vi kan göra med dessa är dock lite begränsat, jämfört med ett riktigt funktionellt språk. Problemet ligger i hur vi kan deklarera en funktions-typ. Java är ett statiskt typat språk, så allt måste ges en typ. I språk som (e.g.) Haskell finns enkel syntax för funktionstyper: f :: Int -> Int Java har historiskt inget sätt att skriva ut funktionstyper, och de som designade Java 8 ville inte göra för stora avsteg från Java s kärna.
Functional Interface Ett functional interface i Java är ett interface som deklarerar exakt en metod: @FunctionalInterface public interface MyFunction { public int thefunction(int x); } Vi kan använda lambda expressions som short-hand för objekt som implementerar ett sådant functional interface, e.g. MyFunction f = x -> x+5; int y = f.thefunction(5);
Lambda syntax Ett lambda expression i Java har följande syntax: En lista av parametrar, e.g. (x,y,z) Om vi bara har en parameter kan vi utelämna parenteserna. Om vi inte tar något argument alls skriver vi () (Lustigt nog har vi inget lambda först.) En pil: -> En method body: { return x+5; } Om vår body består av bara ett expression vars resultat ska returneras behöver vi varken {} eller return, vi skriver bara uttrycket: x+5 (x,y) -> x+y; x -> x+5; s -> { System.out.println(s); }; () -> 42; Exempel på giltiga lambda expressions i Java.
Övning Börja från koden som finns att ladda ner från hemsidan. Vi har ett nytt package DIT952.macro, som i nuläget är ganska tomt. Resten av koden ser ut precis som den gjorde efter föreläsningen igår. Vårt mål med dagens övning är att skapa makron objekt som representerar en sekvens av transformationer över polygoner, och som kan appliceras när så önskas. I DIT.macro finns ett interface Transform. Detta ska vara ett functional interface, med en enda metod transform, som representerar en transform av en polygon. Vilka argument- och retur-typer bör metoden ha? Deklarera denna metod. Fyll i exempel-klassen ExampleTransform som implementerar detta interface. Klassen Macro representerar en sekvens av transformationer, som ska kunna appliceras som en enhet. Transformationer ska kunna läggas till med metoden addtransform. Implementera denna metod. Implementera en metod transform i Macro som applicerar alla transformer som lagrats. Vilka argument- och retur-typer bör denna metod ha? (Är ett Macro en Transform?)
Övning forts. Nästa steg blir att använda oss av dessa macron: I PolygonModel finns metoden update, som anropas av animate. Uppdatera dessa metoder så de tar ett Macro-objekt som argument, och baserar animationen på detta, istället för det nuvarande hårdkodade beteendet. I DrawPolygons.main, skapa ett Macro som ni ger som argument till anropet till animate. Lägg till några transformationer till detta Macro. I anropet till addtransform, använd först ExampleTransform. Byt sen ut detta till att använda ett lambda-uttryck som gör samma sak. Vad heter det design pattern vi just implementerat? För mer utmaning, utan inbördes ordning: Låt animate ta en lista av macron, och skicka dem ett och ett till update. Börja om från början när ni når slutet av listan. Vad skulle det krävas för att vi ska kunna skicka argument till våra makron? Kan ni implementera en bra lösning? Lägg till en Controller som låter användaren dynamiskt lägga till fler transformer i de(t) macro som animeras, och/eller fler macron i listan som animate använder.