Storseminarium 2.1 - En sak i taget
Innan seminariet ska du ha gått igenom Inför seminariet nedan och gjort tillhörande quiz. Syftet med detta är att du ska bekanta dig med innehållet så eventuella frågor kan redas ut under seminariet.
Denna sida visar en del av det som kommer att diskuteras på seminariet. Det kan hända att handledarna också tar upp andra uppgifter som inte behöver något specifikt studiematerial och då syns dessa uppgifter inte på sidan.
Inför seminariet
Under seminariet
Vi går igenom nedanstående uppgifter tillsammans, det kommer finnas möjlighet till diskussion och frågor. Känn er fria att följa med på uppgifterna på egen dator under seminariet om ni lär er bättre så, men vi kan inte garantera att vi har tid att vänta in alla.
Pythontutor
Använd pythontutor.com för att stega igenom nedanstående kodexempel:
Summa från 0 till något heltal n
|
|
Summera lista (från föreläsningen)
|
|
Telephone game
Målet är att förstå:
- Hur man identifierar basfallet (när rekursionen ska sluta)
- Hur man definierar det rekursiva fallet (när funktionen ska anropa sig själv)
- Hur data förändras steg för steg i en rekursiv kedja
Telephone game (viskleken) är en lek som går ut på att skicka ett meddelande genom en sekvens av personer som återberättar meddelandet så noggrant som möjligt. Detta resulterar oftast i att meddelandet sakta ändrar mening, det kan handla om att ord byts ut till ett annat ord som låter snarlikt, eller att strukturen förändras
Vår uppgift är nu att skriva ett program som använder enkelrekursion för att simulera en sådan lek. Funktionen telephone_game ska vara enkelrekursiv, och tar emot två parametrar; phone_list, som är en lista över namn på kompisar i den ordningen som meddelandet ska berättas; message, är en sträng som representerar meddelandet som varje kompis har uppfattat från tidigare samtal.
Uppgift: Skriv klart funktionen telephone_game i koden som du kan kopiera från i kurskatalogen /courses/729G46/kursmaterial/storsem/2_1
(kopiera hela katalogen med cp -r
). En zipfil kan också laddas ner här. Vi ska använda mutate
för att förändra meddelandet.
Förslag på lösningsstrategi
- Kolla om det är basfallet (inga personer kvar)
- Om basfall:
- Returnera meddelande
- Annars (rekursivt fall):
- Skriv ut vem som tar emot meddelandet
- Förvanska meddelandet
- Skriv ut vad personen hörde
- Anropa telephone_game med listan utan första namnet och det nya meddelandet
|
|
Att diskutera
- Uttrycker vi en iterativ processlösning eller en rekursiv processlösning? Varför?
Lösningen beskriven i telephone_game_iterproc
är troligtvis den mest naturliga och uttrycker en iterativ processlösning eftersom vi i varje steg utför alla beräkningar för en person innan vi gör det rekursiva anropet. Ett annat sätt att se detta är att returvärdet för alla rekursiva anrop kommer vara detsamma, dvs. den slutgiltiga formen av meddelandet.
- Kan vi konvertera till den andra typen och hur skulle det se ut?
Lösningen beskriven i telephone_game_recproc
uttrycker en rekursiv processlösning eftersom vi utför operationerna för vad en viss person hör först efter att vi gjort det rekursiva anropet. Ett annat sätt att tänka på det är att returvärdet från varje rekursivt anrop kommer vara mer och mer muterat tills vi är tillbaka vid det första anropet, snarare än att argumentet till varje anrop kommer vara mer och mer muterat.
- Hur kan vi modifiera lösningen för att samla alla versioner av meddelandet i en tupel istället för att skriva ut dem?
Lösningen beskriven i telephone_game_acc
samlar delstegen i en tupel utan att göra några utskrifter själv. Notera att den här lösningen inte uttrycker en rent iterativ processlösning eftersom vi utför konkateneringen av av tuplerna först efter att vi gjort det rekursiva anropet. Anropet står efter +
-tecknet, men själva konkateneringsoperationen kan inte utföras förrän båda operanderna har beräknats, så rekursionen kommer att utföras först.
Samtidigt sker ju muteringen före det rekursiva anropet och dess resultat skickas vidare så vi skulle kunna säga att genereringen av meddelandena följer en iterativ process medan genereringen av tuplerna följer en rekursiv process. Detta kan såklart bli förvirrande så en rent iterativ processlösning finns i telephone_game_acc_iterproc
. (Det finns också en rent rekursiv processlösning i telephone_game_acc_recproc
, men den är inte vacker och vad den mest illustrerar är att man nog inte ska göra på det sättet.)
- Hur fungerar den verkliga situation som motsvarar vår lösning? Är den första personen i listan den som säger det ursprungliga meddelandet, eller är hen den första som hör det ursprungliga meddelandet och vad innebär det för i vilken ordning saker sker i simuleringen? Kan vi ändra vår tolkning och behöver vi i så fall modifiera koden?
I de absolut första lösningarna är det uppenbart att någon utanför listan med namn viskar det ursprungliga meddelandet till den första personen i listan eftersom vi uttryckligen skriver ut att den första personen hör ett muterat meddelande. Det fortsätter dock att vara sant eftersom vi i samtliga lösningar har 5 namn och 5 stegvis muterade versioner av ursprungsmeddelandet.
Det måste inte vara så dock. Vi skulle kunna anta att den första personen i listan säger ursprungsmeddelandet och den sista personen ropar vad de hörde. Vi kan säga att vi betraktar listan som sluten eftersom ingen implicit extra person ingår kedjan och både den första och sista personen ingår. Kod för att modellerad det finns i telephone_game_closed
ovan.
- Kan vi modifiera lösningen för att skicka meddelandet i motsatt riktning genom listan av personer utan att ändra typen av lösning? Hur?
Vi bara ändrar i vilken ordning vi konsumerar elementen i phone_list
. Dvs. istället för att behandla phone_list[0]
och skicka phone_list[1:]
till nästa anrop så behandlar vi phone_list[-1]
och skickar phone_list[:-1]
till nästa anrop.
Sidansvarig: Johan Falkenjack
Senast uppdaterad: 2024-07-26