Flöde och State

Att programmera är att ge instruktioner till en dator, eller snarare datorns processor.

En processor kan bara göra en sak åt gången, och instruktionerna utförs därför en efter en, i ett flöde.

Under flödets gång kommer variabler att skapas och deras värden uppdateras.

State är värdet på alla variabler i ett program, vid ett givet tillfälle.

Programmets state ändras alltså allteftersom programmet körs.

Att programmera handlar därför om att skapa ett flöde som bearbetar state och ser till att programmet har rätt state när det är klart.

Man kan alltså se flödet som en serie av transformationer av state.

För att konstruera programmets flöde och för att transformera state finns ett begränsat antal strategier som används av alla programmerare oavsett vilka program de skriver eller språk de använder.

Genom att kombinera dessa strategier på olika sätt, kan man skapa alla program.

Strategierna är oberoende av kod, men kan så klart implementeras i kod i valfritt programmeringsspråk.

Den här boken går igenom de strategier man behöver för att klara Programmering 1 (och antagligen bra mycket mer än så).

Flödesschema

För att illustrera strategier används flödesscheman.

Flödesscheman fungerar såhär …​

Mål och Strategier

Här behövs text om hur programmerare sätter upp mål- och delmål och hur de använder strategier för att uppnå dessa mål- och delmål. Gärna med praktiska exempel.

Strategier

Ändring av state (transformation)

Tilldelning

Är tilldelning en strategi eller räknas det som programming "knowledge"?

För att kunna använda värden (t.ex tal) i program måste man först lagra dem i en variabel. Att lagra ett värde i en variabel gör man med hjälp av tilldelning.

En tilldelning består av tre komponenter: en variabel, ett tilldelningstecken och ett värde.

  • Ruby

  • Python

  • Javascript

  • C#

Tilldelningsstrategin i Ruby
speed = 10
speed = 10
const speed = 10;
var speed = 10;

Initialisering

Initialisering används när man vet att man kommer behöva ett värde som man kan modifiera längre fram i flödet.

Exempel: Summera tal

När man vill räkna ut summan alla värden i en lista behöver man ha en variabel som innehåller summan. För varje värde i listan vill man sen addera värdet till summa-variabeln. Men för att man ska kunna addera det första värdet i listan till summa-variabeln måste summa-variabeln först vara initialiserad med ett värde, antagligen 0.

Exempel: Bilspel

I ett bilspel vill man kunna gasa och bromsa. Både gas- och bromskoden kommer modifiera hastigheten på bilen, men för att hastigheten ska kunna modifieras måste det först skapas en variabel som innehåller hastigheten, och variabeln måste ha initialiserats med ett värde som kan modifieras.

Initialiseringsstrategin
  • Ruby

  • Python

  • Javascript

  • C#

speed = 0 (1)

...

if pressed_button == 'w'
    speed += 1 (2)
elsif pressed_button == 's'
    speed -= 1 (2)
elsif pressed_button == 'esc'
    speed = 0  (2)
end
1 Initialisering av speed-variabeln
2 Modifiering av speed-variabeln
speed = 0
const speed = 0;
var speed = 10;

Inkrementering

Inkrementering innebär att öka värdet på en variabel. Oftast är värdet ett heltal. Inkrementering används ofta inne i loop-strategierna för att hålla koll på räknar-variabeln, men det går även att använda tillsammans med de olika if-strategierna.

För att inkrementera värdet på en variabel måste variabeln först vara initialiserad

Inkrementering med if och if-elsif
  • Ruby

  • Python

  • Javascript

  • C#

healthiness_score = 0 (1)

...

if favourite_drink == 'water'
    healthiness_score += 1 (2)
end

if favourite_food == 'fruit'
    healthiness_score += 1 (2)
elsif favourite_food == 'carrot'
    healthiness_score += 2 (2)
elsif favourite_food == 'pizza'
    healthiness_score -= 2 (3)
end
1 Initialisering av healthiness-variabeln
2 Inkrementering av healthiness-variabeln
3 Dekrementering av healthiness-variabeln
speed = 0
const speed = 0;
var speed = 10;
Inkrementering i räknande loop
  • Ruby

  • Python

  • Javascript

  • C#

number_of_greeted_people = 0 (1)

...

while number_of_greeted_people < number_of_people
    puts "Hello, nice to meet you!"
    number_of_greeted_people += 1 (2)
end
1 Initialisering av number_of_greeted_people-variabeln
2 Inkrementering av number_of_greeted_people-variabeln
speed = 0
const speed = 0;
var speed = 10;

Dekrementering

Dekrementering innebär att minska värdet på en variabel. Oftast är värdet ett heltal. Dekrementering används ofta inne i loopar för att hålla koll på räknar-variabeln, men det går även att använda tillsammans med if-strategierna.

För att dekrementera värdet på en variabel måste variabeln först vara initialiserad

Dekrementering med if och if-elsif
  • Ruby

  • Python

  • Javascript

  • C#

healthiness_score = 0 (1)

...

if favourite_drink == 'water'
    healthiness_score += 1 (2)
end

if favourite_food == 'fruit'
    healthiness_score += 1 (2)
elsif favourite_food == 'carrot'
    healthiness_score += 2 (2)
elsif favourite_food == 'pizza'
    healthiness_score -= 2 (3)
end
1 Initialisering av healthiness-variabeln
2 Inkrementering av healthiness-variabeln
3 Dekrementering av healthiness-variabeln
speed = 0
const speed = 0;
var speed = 10;
Dekrementering i räknande loop
  • Ruby

  • Python

  • Javascript

  • C#

number_of_laps_left = 5 (1)

...

while number_of_laps_left > 0
    puts "Running a lap!"
    number_of_laps_left -= 1 (2)
end
1 Initialisering av number_of_laps_left-variabeln
2 Dekrementering av number_of_laps_left-variabeln
speed = 0
const speed = 0;
var speed = 10;

Mellanlagring

Mellanlagring används när man vill återanvända värdet från en uträkning eller ett funktionsanrop senare i flödet. Exempelvis för att funktionsanropet kräver mycket resurser, tar lång tid att genomföra, eller kräver input från en användare, eller för att det bara blir tydligare kod.

Exempel: Lagra användares initialer

Istället för att varje gång man vill använda en användares initialer extrahera dessa från variabeln som innehåller användarens namn, kan man extrahera dem en gång och mellanlagra resultatet i en variabel.

Exempel: Hur många gånger förekommer ordet i boken?

Ett program ska jämföra vilket av två ord som förekommer flest antal gånger i en bok. Det tar relativt lång tid att söka igenom boken och räkna antalet förekomster av ordet. Därför kan man räkna anatalet förekomster en gång, och lagra resultatet i en variabel, som man sedan använder varje gång man vill använda värdet.

  • Ruby

  • Python

  • Javascript

  • C#

initials = "#{first_name[0].capitalize}.#{last_name[0].capitalize}." (1)

...

puts "Your initials are: #{initials}" (2)
1 Mellanlagring av värdet.
2 Användning av värdet.

Python

Javascript

C#

Konkatenering

Är det här en strategi?

Konfigurationslagring

Konfigurationslagring används när man vill använda ett värde längre fram i flödet, men man vill inte skriva ut värdet direkt, utan vill kunna använda en variabel med ett beskrivande namn istället för att skriva värdet direkt.

Exempel: Priser med och utan moms

Ett program som ska visa priser med och utan moms. Istället för att skriva pris * 1.25 kan man skriva pris * moms, förutsatt att man i moms-variabeln lagrat värdet 1.25.

Exempel: Kastbanor med gravitationskonstant

I ett program som ska räkna ut kastbanor kan man lagra gravitationskonstanten (9.807) i variabeln gravitation och använda den istället för värdet varje gång man behöver använda gravitationskonstanten.

Exempel: Spara återkommande textfraser

I Bröderna Lejonhjärta-spelet ska alla vakter avsluta sina meningar med frasen "All makt åt Tengil vår befriare!". Istället för att skriva frasen på alla ställen kan man lagra frasen i en variabel och använda variabeln vid varje tillfälle.

Konfigurationslagring gör koden tydligare att förstå för oss människor (datorn bryr sig inte), och gör det enklare att ändra - om man behöver ändra det man lagrat behöver man bara ändra på ett enda ställe.

Sinatra Logo
  • Ruby

  • Python

  • Javascript

  • C#

vat = 1.25 (1)

...

puts "#{price} exkl moms (#{price * vat} inkl. moms)" (2)
1 Konfigurationslagring av momssatsen (vat står för Value Added Tax, (moms på engelska)),
2 Användning av momssatsen.
gravitation = 9.807
const gravitation = 9.807;
var gravitation = 9.807;
Type inference räknar ut vilken datatyp som lagras i variabeln. Även om det inte står att variabeln innehåller en specifik datatyp kommer variabeln fortfarande vara "låst" till den datatyp som initialt lagrades i variabeln (i det här fallet en int).

Swap

Swap används när du behöver byta plats på två värden i ett program.

Exempel: Byta plats på värden i en array

Som en del av en in-place-sorteringsalgoritm behöver värden i en lista byta plats, t.ex vill man byta plats på 9 och 5 i följande lista: [9,7,5]

Exempel: Byta plats på tecken i en sträng.

Om man vill skapa anagram kan man byta plats på tecken i sen sträng, t.ex kan man ändra "takt" till "katt" genom att byta plats på t (det första) och k.

Exempel: Byta plats på namn.

I vissa delar av världen presenterar man sig med förnamn, och sen efternamn, i andra delar av världen med efternamn, och sen förnamn. Om man har två variabler för namn, kan man därför vilja byta plats på vad som lagras i variablerna.

För att genomföra swap-strategin behöver du först ha referenser till de två värden du vill byta plats på. Referenserna kan vara variabler som innehåller själva värdena eller ett index i en lista (där värdet finns).

Svårigheten uppstår när man försöker byta plats. Tänk följande pseudokod

Problemet med att byta plats
a = 1
b = 2
a = b (1)
b = a (2)
1 Värdet på a skrivs över med värdet på b. (a är 1 och b är 1). Det tidigare värdet på a är förlorat.
2 Värdet på b skrivs över med det nya värdet på a (som är samma som b).

Man kan göra en jämförelse till copy/paste på en dator. Om du kopierar något, och sen klistrar in det på ett annat ställe, skriver du över det som fanns på det andra stället tidigare.

För att kunna spara värdet på a behöver vi använda mellanlagring för att temporärt lagra värdet på a, innan vi skriver över a med värdet på b.

Swap med mellanlagring
a = 1
b = 2
tmp = a (1)
a = b (2)
b = tmp (3)
1 Värdet på a mellanlagras i tmp.
2 Värdet på a skrivs över med värdet på b. Det tidigare värdet på a finns kvar i tmp.
3 Värdet på b skrivs över med värdet på tmp.
Swap-strategin
Swap som flödesschema

Uppdelning av flöde (selektion)

If

Om du vill att ditt program ska göra en sak enbart om ett villkor är sant, kan du använda if.

If-strategin använder ett villkor (ett påstående som kan vara sant eller falskt), och om villkoret utvärderas till sant kommer något ske. Om villkoret inte utvärderas till sant kommer programflödet fortsätta efter villkoret, som om ingenting hänt.

Exempel: Pris med eller utan moms.

På en hemsida som framförallt säljer till företag visas priserna utan moms. Men om någon klickat i att de vill se priserna med moms, ska priserna modifieras med momsen

If-strategin
  • Ruby

  • Python

  • Javascript

  • C#

if show_price_with_vat?
    price = price * vat
end
if show_price_with_vat:
    price = price * vat
end
null
Null
Exempel: Ett till exempel

Exempeltext

If-else

If-elsif

If-elsif-else

Lorem

  • Ruby

  • Python

  • Javascript

  • C#

Ruby

Python

Javascript

C#

Ipsum

  • Ruby

  • Python

  • Javascript

  • C#

Ruby

Python

Javascript

C#

Upprepning av flöde (iteration)

Räknande Loop

En räknande loop används när …​

Inkrementerande Loop

En inkrementerande loop används när …​

  • Ruby

  • Python

  • Javascript

  • C#

Ruby

Python

Javascript

C#

Dekrementerande Loop

En inkrementerande loop används när …​

  • Ruby

  • Python

  • Javascript

  • C#

Ruby

Python

Javascript

C#

Loop Med Brytvärde

Behöver utvecklas (alla loopar är väl egentligen loopar med brytvärde, men själva intentionen är väl det som skiljer).

Avbrott av flöde

Är detta en grupp av strategier?

Tidigt avbrott

Är detta en strategi? (och ska den i så fall ligga här eller under upprepning av flöde?)

Sammansatta strategier

Iterativt uppbyggd output

Iterativt uppbyggd output används när man har en mängd data (ofta en lista) att behandla, och output är beroende av datan.

I iterativt uppbyggd output initialiserar man först output-variabeln med ett lämpligt värde som vi sedan kan modifiera.

Sedan itererar man över datan man behöver behandla och modifierar i iterationen output-variabeln (t.ex genom att addera värden till den)

Slutligen, när iterationen är klar kommer output-variabeln innehålla rätt värde, och man kan returnera den.

Exempel: Skapa en lista av alla ord som börjar med en given bokstav i en text

Först initialiserar vi output-variabeln med lämpligt värde, i det här fallet antagligen en tom lista (som kan innehålla alla ord vi hittar).

Sen itererar vi (med lämplig strategi för uppreping av flödet) över orden och i varje varv i iterationen använder vi if-strategin för att modifiera output-variabel-listan om om ordet börjar med den givna bokstaven.

Slutligen, när iterationen är klar kommer output-variabel-listan innehålla alla ord som efterfrågades, och vi är klara

Lämpliga värden att initialisera output-variabeln med är ofta:

  • 0 (om output ska vara ett tal)

  • en tom sträng (om output ska vara en sträng)

  • en tom lista (om output ska vara en lista)

Men det finns undantag, t.ex kan man ibland initialisera output-variabeln till ett av värdena som finns i mängden man ska behandla.

Switch Loop

Är detta en strategi?

Switch Loop?

Kombinering av strategier

Sammanfogning

Nästning

Ihopvävning

Strategibaserade Uppgifter

Strategi 1

Uppgift 1

Uppgift 2

Strategi 2

Uppgift 1

Uppgift 2

Sinatra Logo