Föreläsning 5 i programmeringsparadigm.

Relevanta dokument
Föreläsning 4 (och 5?) i programmeringsparadigm.

Föreläsning 4 (och 5?) i programmeringsparadigm.

Enjoy Vattenfallsmodellen i funktionella språk

DD1361 Programmeringsparadigm. Carina Edlund

Enjoy Vattenfallsmodellen i funktionella språk

Föreläsning 4 i programmeringsparadigm.

Funktionell programmering DD1361

Föreläsning 6 i programmeringsparadigm. Tips kring programmering i Haskell och kring labbarna.

Föreläsning 7 i programmeringsparadigm. Ytterligare Högre ordningens funktioner: filter, foldr foldl. Hutton 7.2, 7.3 och 7.4.

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2010/11 moment 9 Sida 1 Uppdaterad

Introduktion till Haskell

Våra enkla funktioner eller procedurer

Nada KTH 2004 jan 12 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

Nada KTH 2003 okt 23 Tentamen Programmeringsparadigm 2D1350 Skrivtid 5 h 8-13

Föreläsning 5 i programmeringsparadigm. Tips kring programmering i Haskell och kring labbarna.

LÖSNINGSFÖRSLAG TENTAMEN PROGRAMMERING I ETT FUNKTIONELLT SPRÅK ML, 5P

Tentamensdag 2002-aug-20 Tentamen i Funktionell Programmering Skrivtid 5 h

Föreläsning 8. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Del : Paradigmer allmänt.

Nada Tentamensdag 2004 okt 18 Tentamen Programmeringsparadigm Skrivtid 5 h

Användarhandledning Version 1.2

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson 2

Dagens föreläsning Programmering i Lisp Fö 5

TDIU01 - Programmering i C++, grundkurs

TDDC74 Programmering: Abstraktion och modellering Tentamen, lördag 27 augusti 2016, kl 8 12

F6: Högre ordningens funktioner. Mönster för rekursion (1) Mönster för rekursion (1b) Mönster för rekursion (2) Högre Ordningens Funktioner

Föreläsning 8. newtype Chess = Chess [(Square, Chessman)] -- data ist f newtype OK -- data istället för newtype krävs om >1 konstruerare.

Programmeringsmetodik DV1 Programkonstruktion 1. Moment 9 Om högre ordningens funktioner. PK1&PM1 HT-06 moment 9 Sida 1 Uppdaterad

Programmering II (ID1019) :00-17:00

Programkonstruktion och datastrukturer. Moment 9 Om högre ordningens funktioner. PKD 2011/12 moment 9 Sida 1 Uppdaterad

Tentamen. Datalogi I, grundkurs med Java 10p, 2D4112, Lördagen den 30 november 2002 kl , salar E33, E34

Introduktion till programmering SMD180. Föreläsning 4: Villkor och rekursion

Introduktion till programmering D0009E. Föreläsning 5: Fruktbara funktioner

Del : Paradigmer allmänt.

Föreläsning 7 Innehåll. Rekursion. Rekursiv problemlösning. Rekursiv problemlösning Mönster för rekursiv algoritm. Rekursion. Rekursivt tänkande:

Några inbyggda funktioner (med resultat!) Introduktion till programmering D0009E. Föreläsning 4: Villkor och rekursion. Modulus-operatorn.

Men först: Några funktioner ur preluden. Introduktion till programmering. Uppgiften. Variationer av uppgiften. Föreläsning 4

Del : Funktionell programmering. I alla deluppgifterna, använd Haskell och skriv typen för de identifierare du definierar.

Introduktion till programmering SMD180. Föreläsning 5: Fruktbara funktioner

Kap9. Operatorn.. Hudak 9.4 sid 11. Fermats förmodan, eller Fermats stora sats säger att. xm + ym == zm har heltalslösningar om och endast om m == 2.

Välkomna till DIT012 IPGO. Tyvärr en bug i Google Docs: Sidnummer stämmer inte alltid. Alla anteckningar börjar på sidan 1.

MATLAB. Python. Det finns flera andra program som liknar MATLAB. Sage, Octave, Maple och...

TDDC74 Lab 04 Muterbara strukturer, omgivningar

Repetition i Pascal. Exemplen fac. Exemplen fac i Pascal. Exemplen fac motivering. Orginalet

Command line argumenter. Objektorienterad Programmering (TDDC77) Vad blir resultatet? Nu då? Ahmed Rezine. Hösttermin 2016

Objektorienterad Programmering (TDDC77)

Introduktion till formella metoder Programmeringsmetodik 1. Inledning

Imperativ programmering. Imperativ programmering konstruktioner i Lisp. Datastrukturer (kap ) arraystruktur poststruktur

Föreläsning 9 i programmeringsparadigm. Paradigmöversikt, paradigmhistoria, paradigmgeografi. Se även föreläsning 1.

Kompilering och exekvering. Föreläsning 1 Objektorienterad programmering DD1332. En kompilerbar och körbar java-kod. Kompilering och exekvering

Imperativ programmering. Föreläsning 2

Programkonstruktion. Tentamen,

Undervisning. Examination

Tentamen i. TDDC67 Funktionell programmering och Lisp

Lambdas. (och fler design patterns) Objekt-orienterad programmering och design (DIT952) Niklas Broberg, 2017

1. Inledning, som visar att man inte skall tro på allt man ser. Betrakta denna följd av tal, där varje tal är dubbelt så stort som närmast föregående

Inlämningsuppgift MiniPlotter

Programkonstruktion och Datastrukturer

Inledande matematik för I1. MVE011 läsperiod Matlab vecka 2 övningsuppgifter

Imperativ programmering

Välkommen till. Datastrukturer, algoritmer och programkonstruktion. eller DOA

String [] argv. Dagens Agenda. Mer om arrayer. Mer om arrayer forts. String [] argv. argv är variabelnamnet. Arrayer och Strängar fortsättning

Kursanalys för Programmeringsparadigm 2D1361, läsperiod 1 och 2 läsåret 2005/2006

Programmeringsteknik med C och Matlab

Beräkningsvetenskap föreläsning 2

SMD 134 Objektorienterad programmering

Föreläsning 2. Variabler, tilldelning och kodblock{} if-satsen Logiska operatorer Andra operatorer Att programmera

Pythons standardbibliotek

Programmering. Seminarier i datavetenskap, datorteknik och informationsteknik. Niklas Broberg

Dagens föreläsning Programmering i Lisp. - Bindning av variabler (avs 14.6) fria variabler statisk/lexikalisk och dynamisk bindning

Multipel tilldelning. Introduktion till programmering D0009E. Föreläsning 6: Iteration. while-satsen. Kom ihåg. Snurror kontra rekursion

Programkonstruktion. Tentamen,

Introduktion till programmering. Standardfunktioner. Vad används datorer till? Standardfunktioner. Föreläsning 2. Prelude. $ ghci...

Klassdeklaration. Metoddeklaration. Parameteröverföring

Datatyper och kontrollstrukturer. Skansholm: Kapitel 2) De åtta primitiva typerna. Typ Innehåll Defaultvärde Storlek

Bakgrund och motivation. Definition av algoritmer Beskrivningssätt Algoritmanalys. Algoritmer. Lars Larsson VT Lars Larsson Algoritmer 1

C++ Funktioner 1. int summa( int a, int b) //funktionshuvud { return a+b; //funktionskropp } Värmdö Gymnasium Programmering B ++ Datainstitutionen

Pascal... Pascal. Pascal... Pascal...

Pascal. reserverade ord fördefinierade funktioner och procedurer egendefinierade funktioner, procedurer och objekt

Universitetet i Linköping Institutionen för datavetenskap Anders Haraldsson

Anmälningskod: Lägg uppgifterna i ordning. Skriv uppgiftsnummer (gäller B-delen) och din kod överst i högra hörnet på alla papper

MMA132: Laboration 2 Matriser i MATLAB

TDP002 - Imperativ programmering

TDDC74 Programmering, abstraktion och modellering DUGGA 2

Grundläggande programmering, STS 1, VT Sven Sandberg. Föreläsning 20

Repetition i Python 3. Exemplen fac. Exemplen fac motivering. Exemplen fac i Python

Tentamen i kurserna Beräkningsmodeller (TDA181/INN110) och Grundläggande Datalogi (TDA180)

TDDC74 PROGRAMMERING: ABSTRAKTION OCH MODELLERING VT 2017

Objektorienterad Programmering (TDDC77)

Styrteknik: MELSEC FX och numeriska värden

Laboration: Whitebox- och blackboxtesting

TDDC30. Kursledning Kursledare: Jonas Lindgren. Labassistent: Jonas Lindgren Labassistent: Niklas Holma Labassistent: Erik Nilsson

I Skapa Hej.java och skriv programmet. I Kompilera med javac Hej.java. I Rätta fel och repetera tills du lyckas kompilera ditt program

TDDC74 Programmering: Abstraktion och modellering Datortenta , kl 14-18

Lågnivåprogrammering. Föreläsning 2 Lågnivåprogrammering. Binära tal. En enkel modell av datorns inre

Programmering. Seminarier i datavetenskap, datorteknik och informationsteknik. Niklas Broberg

Programmering I Tobias Wrigstad fredag, 2009 augusti 28

TDDC74 Programmering: Abstraktion och modellering Dugga 2, , kl 17-19

BEGREPP HITTILLS FÖRELÄSNING 2 SAMMANSATTA UTTRYCK - SCHEME DATORSPRÅK

Transkript:

Föreläsning 5 i programmeringsparadigm. λ-notation (lamda-notation, anonyma funktioner). Hutton 4.5. (Fokker 2.3.4.) Vi kan om vi vill definiera hjälpkonstanter, t ex i denna funktiondefinition : kommunalskatt inkomst = skattesats * inkomst where skattesats = 0.30 -- skattesats definieras som 0.30. Eller med samma "skåp"; icke-lokal definition utan where: kommunalskatt inkomst = skattesats * inkomst skattesats = 0.30 -- skattesats definieras som 0.30. Men om vi är för lata för att "döpa" 0.30 till skattesats så kan vi förstås helt enkelt skriva kommunalskatt inkomst = 0.30 * inkomst Dvs i en definition namngivet begrepp kan ersättas med sin definition. I en vanlig mattebok skulle en definition av kommunskatt de ut då här: kommunalskatt(inkomst) = skattesats * inkomst Matematiker gillar dock inte så långa namn; i regel nöjer man sig med en-bokstaviga namn på definerade begrepp; t ex kan en annan funktion f definieras så här: f(i) = 3i + b, vilket i Haskell kan skrivas så här: f (i) = 3*i + b (mycket vanligare) f i = 3*i + b Blanktecknet mellan f och i betyder funktionsapplikation. Funktionsapplikation har högsta prioritet. Vid definitioner med mer invecklade mönster måste man därför använda paranteser, ex vis straight (Sq a1 b1) (Sq a2 b2) =... -- steg 1 i Schacklabben Likaså i uttryck med mer invecklade argument måste man därför använda paranteser, ex vis... && straight (Sq 3 5) (Sq 2 2)...... + f (3+5) *... Att man glömmer paranteser är nog de vanligaste felet när man börjar använda skriva Haskell-skript.

Ovan skriver vi inte funktioner på samma sätt som konstater; konstater skrivs med konstantnamnet följt av = (defineras som) och ett högerledsuttryck som är konstantens värde. I funktionella språk vill man betrakta även funktioner som namn med värden. Man kan dock inte definiera f så här: f = (3*i + b) --- Fel!!!!!!!! f blir en konstant. eftersom (3*i + b) är ett uttyck men f är en funktion. Dessutom måste ju i definitionen framgå att i är en parameter viket inte b är. Istället skriver man f = \ i -> 3*i + b \är Haskell sätt att skriva den grekiska bokstaven λ. Teoretiskt sett är detta "det riktiga sättet", det alternativa sätt vi använt hittills är "syntaktiskt socker" och en eftergift till konventionell matematik. Parametern, som kan vara ett mönster som förut, skrivs mellan \ och -> ; sedan följer högerledet. I matematiken kan man också skriva funktionen f så här: f = λi.3*i + b Detta kallas λ-notation (lamda-notation), och man använder λ-notation i λ-kalkyl. Haskell Curry, och även bland annat Schönfinkel och Alonzo Church, arbetade med λ-kalkyl på 1930-talet, en gren av matematiken där λ-notationen är ett viktigt begrepp. λ-kalkyl är äldre än datortekniken. Kärnan i funktionell programmering är helt enkelt λ-kalkyl. Haskell Curry har hedrats genom att hans förnamn har namngivit programspråket Haskell och hans efternamn givet namnet på en viktig teknik för att skriva funktioner som behandlas i om en stund. På samma sätt som vi i uttryckkan byta ut skattesats med 0.30 kan vi nu i uttryck byta ut f i... + f (3+5) +.. med sitt värde i lamda-notation... + (\ i -> 3*i + b) (3+5) +... och funktionen kommunalskatt i..* kommunalskatt 100 000 med funktionens värde i lamda-notation..* (\inkomst->0.3*inkomst) 100 000 Vi slipper hitta på ett namn för funktionsvärden, vi använder i stället namnlösa, anonyma, funktioner. Detta är ibland vara bekvämt som vi skall se.

Högre ordningens funktioner; funktioner som lämnar funktioner som resultat. Denna funktion add x y = x + y kan i stället skrivas add = \x -> ( \y -> x + y) add = \x -> \y -> x + y. det vill säga att add är en funktion som givet ett argument, som binds till x, ger som resultat en anonym funktion ( \y -> x +y). Om denna anonyma funktion ges ett argument, som binds till y, får vi ett resultat som är summan av x och y. Exempelvis add 3 5 blir ((\x -> ( \y -> x + y)) 3) 5 blir ( \y -> 3 + y) 5 blir 3 + 5 blir 8 Funktioner har i definitioner bara en parameter. Är resultatet en funktion kan den används för en parameter osv. Funktioner som används i uttryck har bara ett argument. Är resultatet en funktion kan resultatet användas på ytterligare ett argument osv. I Haskell är add 3 ett helt korrekt uttryck, värdet är funktionen som lägger 3 till ett argument. Genom att definera add som ovan får vi gratis möjligheten att anväda add som en partiellt appliserad funktion på engelska a curried function add 3, men vi kan också använda uttryck som add 3 5 som är det samma som (add 3) 5. Man har alltså valt precedensregler för ( ) i uttryck med flera applikationer (blanktecken) så att man slipper skriva ut dem i vissa fall, men i början skadar det inte att man skriver ut "onödiga" paranteser. Om vi i stället definierar en funktion med en parameter som är ett par (ett vanligt men egentligen felaktigt språkbruk är att add1 "är en funktion av två variabler"): add1 (x, y) = x + y som mer påminner om konventionell matematik kan vi bara skriva uttryck som add1(3, 5). Typen för add och add1: add :: Int -> (Int-> Int) add :: Int -> Int-> Int. add1 :: (Int, Int)-> Int Man har alltså valt precedensregler för ( ) i typuttryck så att man slipper skriva ut dem i vissa fall, men i början skadar det inte att man skriver ut "onödiga" paranteser.

Eftersom partiellt appliserade funktioner är flexiblare så brukar Haskell programmerare undvika funktioner som arbetar med par. På samma sätt brukar man inte skriva funktioner som har tripplar som argument utan istället skriva funktioner som har typen... ->.. ->..> och analogt för tuppler i allmänhet. Så har både vi och Hutton i praktiken gjort hela tiden, se t ex definitionen av Herons formel i föreläsning 2. Behöver man då tuppler överhuvud taget?! Jo, som resultat och del i datastrukturer ibland. Enklaste definitonen av add är add = (+), men nu är add :: Num a => a -> a-> a. I konventionell matekmatik är man van vid att argumentet till en funktion är ett uttryck; t ex sin (3.0+4.0), men med funktioner som ger funktioner som resultat kan även det som står till vänster om blanktecknet, funktionen som skall appliseras på argumentet, vara ett uttryck som räknas ut. T ex (add 3) (4*5) som även kan skrivas add 3 (4*5) vilket blir 23. add 3 4*5 är däremot detsamma som (add 3 4)*5 ((add 3 ) 4 ) * 5, blir 35. Funktionsapplikation har högsta prioritet. Operatorsnitt (sections) Hutton 4.6. Även operatorer kan användas partiellt. Vår funktion add skrivs enklast som (3+) (+3). Sådana uttryck kallas operatorsnitt, engelska sections. Se Hutton 4.6 Högre ordningens funktioner med funktioner som argument: map, filter. Hutton kapitel 7. (Fokker 3.1.3, C&K p 37, 38). Funktioner som lämnar funktioner som resultat har alltså minst två -> i sitt typuttryck. Funktioner som har funktioner som argument är också högre ordningens funktioner och har minst två -> i sitt typuttryck och mint ett parantespar ( ). Många funktioner är av högre ordningen på båda sätt. De allra flesta funktionerna i preluden är högre ordningens funktioner. Detta gör att de är generellt användbara och mycket kraftfulla. "Standardsätt" att tänka programmera fångas en gång för alla i funktionsdefinitioner. Två exempel är map och filter. map :: (a->b) -> ([a] -> [b]) -- förändra alla element i en lista på samma sätt. -- ofta med "en "loop" i imperativa språk Argumentet till map är alltså en fuktion (a->b), parantesen måste vara kvar, och resultat en funktion [a] -> [b]. Man kan även skriva map :: (a->b) -> [a] -> [b]. Exempel, vår kära power : power :: Int -> Int -> Int power m n = product (map f [1..n]) where f _ = m

power m n = product (map (\_ -> m) [1..n]) (map kan ersättas med listomfattningar ) power m n = product [ m i <- [1..n] ] Se definitioner på map i Hutton, dels med listomfattning (sid 80), dels med rekursion (sid 81). För att illustrera vad map gör kan man tänka så här: map f [ a1, a2, a3...] blir [f a1, f a2, f a3...]. Till exempel kan en funktion som fördubblar alla elementen i en lista skrivas som doublelist :: Num a => [a] -> [a] doublelist [] = [] doublelist (x:xs) = 2*x : doublelist xs doublelist list = map (2*) list -- vi har glädje av snitt doublelist = map (2*) -- vi har glädje av snitt doublelist = map (*2) -- vi har glädje av snitt doublelist = let f x = 2*x in map f doublelist doublelist = map f where f x = 2*x doublelist = map f where f = \x -> 2*x doublelist = let f = \x -> 2*x in map f = map (\x -> 2*x) f doublelist list = [2*x x <- list] Märk hur definitionen av map map :: (a->b) => [a] -> [b] map f [] = [] map f (x:xs) = f x : doublelist xs är en generalisering av mönster av denna sort där man parametriserat vad som skall hända med alla elementen: doublelist :: Num a => [a] -> [a] doublelist [] = [] doublelist (x:xs) = (2*) x : doublelist xs

filter -- filtera (välj ut) en del element ur en lista. (i st f for-loopar). Se Hutton. För att illustrera vad filter gör kan man tänka så här: filter p [a1, a2,...] testa [p a1, p a2,...]om a1 klarar testen kvar osv[a1,...] Kombinationer av filter och map kan oftast istället skrivas med listomfattningar. När man använder filter och map är det ofta bekvämt att använda λ-notation. Se vidare Hutton. Om map och filter definieras med rekursion kan listomfattning definieras med map och filter. För den som är intresserad av teori: I Haskell gäller ett i en definition namngivet begrepp kan ersättas med sin definition. Att i en definition namngivet begrepp alltid kan ersättas med sin definition är en mycket viktig egenskap hos matematik och funktionella språk. I imperativa språk gäller inte detta, trots att det borde vara en självklarhet, ett exempel i Java: static int x = 4; int z = f(x) int y = z * z; Efter att kört dessa satser är inte y säkert samma värde som när man kört detta program static int x = 4; int y = f(x) * f(x) ; -- z ersatt av sin "definition" Låt t ex f ha denna definition static int f(int u) { int result = 2*u; x = 5; //sidoeffekt return result; } Sidoeffekter ställer lätt till med en massa elände och gör att man i imperativ och objektorienterad programmering måste tänka sig in i vad som händer vid körningen. Sammanhanget (contexten), vad som hänt under körningen och inte bara vad som står i programkoden, spelar ofta roll när man skall tolka något i ett imperativt språk. Ordningen mellan satser spelar (en mycket stor) roll i imperativa språk. Att skriva bra imperativa program innebär att använda minimalt med sidoeffekter ( i OO använda sidoeffekter på ett kontrollerat sätt) och se till att så få begrepp som möjligt samtidigt är relevanta i något sammanhang. Betydelsen av en funktionsdeklaration i ett funktionellt språk beror inte på vad som händer vid en körnming. Funktionsdeklarationer kan stå i godtycklig ordning.

Funktionella språk har inga sidoeffekter, programmeringen innebär att definiera begrepp, dvs lämpliga funktioner och datatyper (och typklasser och i större projekt moduler). Funktionssammansättning. Hutton 7.5. (Fokker 2.3.3) Uttrycket f ( g x ) kan skrivas som (f. f) x let h = f. g in h x. Exempel: map f (map g (map h lista)) skrivs lämpligen map (f.g.h) lista. (man slipper gå igenom listan gång på gång). Märk också likheten mellan Haskells. och i Unix för att göra "pipes". Kommentarer till steg 3b Polygongraphic i Schack-labben ("kanske kursens svåraste uppgift"): Med de kunskaper vi hade tidigare kunde vi skriva polygonpicture med listomfattning, vilket nog också är enklast. Med de kunskaper vi har nu kan vi istället använda map, funktionssammansättning och partiell applikation. Vi har en definitionen vektoradditon från Vector med typen : vadd :: Vector -> Vector -> Vector Antag att vi har en lista med polygonkoordinater poly::[vector] (dvs en pjäs utseende) som skall flyttas till något ställe at::vector (dvs en schackruta). Vi skulle kunna ha användning för något som.. map movedtosq poly... where movedtosq = vadd at -- enklare -- movedtosq coord = vadd at coord -- sämre men det är bekvämt, enklast och bäst att slippa definiera movedtosq.. map (vadd at) poly... vilket är möjligt tack vare att vadd är partiellt applicerbar. På analogt sätt kan man ha glädje av att multiplikation med skalär mscal :: Float -> Vector -> Vector är partiellt appliserbar när vi skall skala polygoner. Antag att vi har en lista med koordinater (en polygon till exempel) flyttas och skalas och räknas om till pixlar. Skrivs lämpligen som map ( tillpixlarfunktion. flyttfunktion. skalfunktion) lista.

Användbara funktioner; until. Fokker 2.3.2 En mängd användbara funktioner finns som redan betonats i Preluden, där de också är definierade, de allra flesta med några få rader Haskell. Att använda dessa funktioner är bekvämt, man slipper göra ungefär samma sak gång på gång, programmering blir mindre tjatigt och programmeringen går ännu fortare, programmen blir kortare och programmering blir på "högre nivå", bekväm och lustfylld. Man kan naturligtvis själv också göra högre ordningens funktioner, och gör man dem bra (bl a så polymorfa som möjligt) så kan dom vara användbara gång på gång i en mängd olika sammanhang. Många av dom högre ordningens funktioner som finns i Preluden är väldigt användbara, t ex foldr och foldl, se Hutton 7.3 och 7.4. Ytterligare ett exempel för den som saknar slingor ("loopar") : until -- förvandla något gång på gång så länge något gäller (~while-loopar). I Prelude : until :: (a -> Bool) -> (a -> a) -> a -> a until p f x = if p x then x else until p f (f x) snyggare med vakter until p f x p x = x otherwise = until p f (f x) Obs. svansrekursiv, dvs det rekursiva fallets högerled är ett utryck som bara består av en applikation av until på nya argument. Detta gör att beräkningen blir minneseffektiv, jämför med power med och utan ackumulering i parameter i föreläsning 2 och fib i lab 1. foldl är svansrekursiv, men inte foldr. Motsvarigheten till "loopar" (slinger, snurror) i imperativa språk kan programmeras med until, och många av våra lösningar med "ackumulering i parametrar" kan också lösas med until. De "imperativa programmeringsvariablerna" motsvaras av komponenterna i en tuppel, "<status>": Java : Haskell : while <not p> { until p f <status> <f > where p :: <statustyp> -> Bool } p <status> =.. - -funktion som blir True när vi skall sluta f :: <statustyp> -> <statustyp> f <status> =..- -funktion som beskriver "loopens kropp" Exempel, vår kära power: power :: Int -> Int -> Int -- accumulerande lösningar med until, power m n n<0 = error " second argument till power >= 0" otherwise = snd (until p f (0, 1)) where p (i, _) = ( i == n )) f(i, acc) = (i+1, acc*m) I Java : static int power (int m, int n) { //snurra, lokala variabler if (n < 0) { throw new RuntimeException("second argument till power >= 0"); } else { int acc = 1; for (int i = 0; i<n ; i = i+ 1) { acc = acc*m; } return acc; } } // Alla sätt att resonera kan fångas med funktioner!