DD1366 Programmeringsparadigm 6,0 hp
Tillfälleskod | Termin(er) | Period(er) | Föreläsare |
---|---|---|---|
52149 | VT2025 | 3 | Marcus Dicander |
Föreläsningsanteckningar.
Inledning/föreläsning 0
Programmeringsparadigm: Handlar om att lyfta fram bakomliggande modeller och idéer bakom program och programmeringsspråk och jämför dessa sida vid sida. För att göra detta kommer vi att titta på språk som skiljer sig mcket åt, t.ex. PHP och Haskell.
Interpretering: översättning mellan programmeringsspråk, on the fly.
Kontrollflöde: if
/while
Föreläsning 1: Funktionell programmering, del 1
Funktionell programmering: En programmeringsstil vars grundläggand operation är funktionsanrop. En vidareutveckling av lambdakalkylen (konstanter, variabler, funktioner och funktionsanrop/tillämpningar - även uttryck, vilket följer av de 4 nämnda "axiomen").
I Haskell är allt immutable (oföräderligt). Underläggar parallellisering.
Kodexempel:
main::IO()
main = -- Observera att main är en oren funktion (modifierar I/O)
putStrLn "Hello world!" -- funktion med bieffekt
I vanliga Haskell-funktioner finns inget returvärde, utan värdet representerar funktionen.
Rekursion
Svansrekursion: Det rekursiva anropet returnerar direkt utan några kvarhängande operationer. Svansrekursiva anrop kan optimeras bättre av GHC, men se upp med '++'!
Ett exempel:
collatzList::Integer -> [Integer]
collatzList 1 = [1] -- Basfall
collatzList n = n : collatzList (collatzStep n) -- Effektivt att lägga till n i början av listan (++ långsammare)
where collatzStep n
| odd n = 3 * n + 1 -- if odd(n) ...
| otherwise = n `div` 2 -- else ...
collatzList
är inte svansrekursiv, eftersom :
blir en kvarhängande operator.
Lat evaluering
Haskell har lat evaluering - väntar med att beräkna saker tills de verkligen behövs. Stora beräkningsträd kan byggas upp av funktionsanrop som beror på varandra. När sedan värdet behövs, kan Haskell tillämpa sina optimeringar och köra alltsammans.
T.ex. orsakar let infinite = [1..]
inga problem, och vi kan t.o.m. köra take 42 infinity
. Att försöka printa ut hela listan leder dock till oändlig rekursion.
Kör vi take 10 (collatzList 27)
kommer Haskell enbart att räkna ut de första 10 talen med collatzList-funktionen, eftersom det är de enda talen som behövs. Detta är väldigt användbart ur prestandasynpunkt!
Listomfattningar
I matematiken kan vi skriva \([x|x\in\{1,2,3,4\},\text{odd}\ x]\), vilket i Haskell kan skrivas som [x | x<-[1..4], odd(x)]
.
Exempel: [mod 73 d | d<-[2..72]]
innehåller alla rester vid division av 73 med 2..72. Vi kan kolla om elem 0 <...>
, vilket ger False
(73 ej jämnt delbart med något sådant tal, dvs. 73 är ett primtal).
Definitionen av primtal 2-1000: [x | x<-[2..1000], notElem 0 [mod x y | y<-[2..(x-1)]]]
Föreläsning 2: Funktionell programmering, del 2 (22/1-2025)
Flyttal
Det finns 252 tal i varje fönster.
Stark och svag typning
Java, Haskell, Python är starkt typade.
- Statisk typning: Sker vid kompilering. T.ex. Java, Haskell. "Nästan alla typfel upptäcks".
- Dynamisk typning: T.ex. Python ("duck typing")
Typsäkerhet
Ett typsystem är säkert om det garanterar att inga uttryck kan anta värden som inte är definierade av typen.
Implicita & explicita typkonverteringar
T.ex. Haskell:
i = 1::Int
t1 = (fromIntegral i)::Double
:t fromIntegral -- fromIntegral :: (Integral a, Num b) => a -> b
i2 = fromIntegral t1::Int -- error
(length lista) / 10 -- error
(fromIntegral (length lista)) / 10 -- explicit typkonvertering med fromIntegral
-- Typsignatur: fromIntegral :: (Integral a, Num b) => a -> b
Egna typnamn
T.ex. type Coord = (Float, Float)
definierar Coord
som en tupel av två stycken Float
.
Fungerar även med polymorfa typer: type AssocList a b = [(a, b)]
(a
och b
är typvariabler).
Typsignaturer (Haskell)
Skrivs ovanför (funktioner) eller efter (anonyma funktioner).
Exempel: isEven :: Int -> Bool
Typinferens
Haskell har lat typinferens - om ingen typ avges kommer typen att bestämma senare, av kontext.
Exempel:
t1 = (3, "små", "grisar")
:t t1 // t1 :: Num => (a, String, String)
head "Maskens huvud" // 'M'
tail "Maskens huvud" // "askens huvud"
Typklasser
Förekommer ofta i typsignaturer och ställer krav på deras typvariabler. T.ex. Num
(numeriska), Ord
(ordnade), Eq
(jämförbara m. likhetsoperatorn ==
), Show
...
Arv hos typklasser
"Varje Ord
-typ måste också vara Eq
."
Exempel:
import Data.Char
import Numeric
-- Typklassen Incrementable
class Incrementable a where
inc :: a -> a -- för att kalla dig för "Incrementable" måste typen implementera "inc"
inc2 :: a -> a
inc2 x = inc (inc x) -- default-implementation av inc2
instance Incrementable Integer where
inc x = x + 1
instance Incrementable Int where
inc x = x + 1
instance Incrementable Char where
inc c = chr ((ord c) + 1)
inc2 c = chr ((ord c) - 32) -- ersätter default-implementationen för "inc2"
Algebraiska datatyper (ADT)
data Color = RGB Double Double Double -- "kombinerad konstruktor/typsignatur"
deriving (Show, Eq) -- "Show" (stringify-bar), och "Eq" (jämförelse av likhet)
-- Getters/accessors
red (RGB r g b) = r
green (RGB r g b) = g
blue (RGB r g b) = b
brightness :: Color -> Double -- typsignatur
brightness (RGB r g b) = sqrt((r^2+g^2+b^2) / 3)
black = RGB 0 0 0
white = RGB 1.0 1.0 1.0
makeColorRGB r g b = RGB r g b -- funktion som skapar en RGB
En algebraisk datatyp är statisk (inga setters), och allt är publikt.
Record syntax
Record syntax -- en alternativ syntax för att skapa en ADT. "Getters" skapas automatiskt.
Nackdel: "Äter upp" namnen -- går ej att återanvända fältnamn (inom samma modul).
Exempel:
data Record = Record { name :: String, achievement :: String, measurement :: Double } deriving(Show, Eq)
Polymorfism
- Ad hoc-polymorfism: T.ex. operator-/funktionsöverlagring. Sker i compile time.
- Parametrisk polymorfism: T.ex. templates i C++ och generics i Java.
- Samma kod kan köras på många olika typer, eftersom typen har abstrakteras bort.
- T.ex. typsignaturen
length :: [a] -> Int
dära
är en typvariabel.
- Subtyping polymorfism (dynamisk bindning): T.ex. arvshierarkier för klasser i C++/Java. Sker i runtime.
- En ny form av polymorfism (1980-tal).
Obs! För ALLA labbar i kursen räcker det att använda immutable (dessutom REKOMMENDERAT att göra så). Förändringsbarhet behövs inte för någon labb, inte ens de betygshöjande.