1. Datoranvändning, matematiska program
Aarne Ranta
Datorintroduktion 2009, D och DV, Chalmers & GU
%!target:html
%!postproc(html): #NEW
%!postproc(html): #HR
#NEW
==Den här kursen==
Introduktion till
- datoranvändning
- programmering
- datavetenskap
Utformad för dem som vet och skall veta allra mest om datorer och programmering
- D-linjen på Chalmers
- DV-linjen på Göteborgs Universitet
#NEW
==Webbsidan==
Hur hittar man den: från svårast till lättast
0. Navigera i Chalmers studieportal
```
http://www.student.chalmers.se/
```
1. Anteckna URL (Uniform Resource Locator)
```
http://www.cs.chalmers.se/~aarne/datorintro/
```
2. Googla med
```
datorintroduktion D-linjen Chalmers
```
3. Googla med läraren
```
Aarne Ranta
```
tryck på "Datorintroduktion"
#NEW
==Kursens uppbygnad==
Vi går snabbt genom [kurswebbsidan ..], för att förklara
- vad man ska lära sig under kursen
- hur man ska göra för att klara kursen
#NEW
==Datavetenskap==
**Datavetenskap** (Computer Science) har sina rötter på två håll:
- matematik
- elektronik
Datavetenskap kan därför se rätt så olika ut beroende på
datavetare.
#NEW
==Hårdvara och mjukvara==
hårdvara = maskinvara, mjukvara = programvara
```
mjukvara
användarprogram -- Firefox, emacs, GHC
operativsystemet -- Windows, Unix, Symbian
-------------------------------------------------------------
hårdvara
datorn -- PC, Mac, iPhone, PSP
```
#NEW
==Operativsystemet Unix==
Första versionen i 1970
Känns numera under namnen Linux, Mac OS X, SunOS, BSD...
Fungerar på alla sorters maskiner
Populärt bland professionella programmerare och datavetare
- användaren kan lätt programmera systemet
- relativt bra säkerhet
- "känns rätt" p.g.a. enkelhet, tydlighet, modularitet, ortogonalitet, öppenhet
#NEW
==Huvuddelarna i Unix==
Kärnan (Eng. kernel): närmast hårdvaran
Filsystemet: kataloger och filer
Kommandotolken (Eng. shell): närmast användaren
Därtill:
- drivrutiner
- fönstersystem
- grafiska gränssnitt
#NEW
==Shellkommandon==
När man matat in användar-ID och lösenord, kommer man oftast in i ett
fönstersystem.
Man kan då öppna ett "shell", som kan heta "terminal", "konsole", "xterm",
"cygwin", etc.
I shellen kör vi följande kommandon (vart och ett efter prompten ``$``):
```
$ whoami -- visa mitt användarnamn
$ pwd -- print working directory
$ ls -- lista innehållet i biblioteket
$ mkdir datorintro -- skapa bibliotek för kursen
$ cd datorintro -- gå till det nya biblioteket
```
För mera information: see Unix-kompendiet (kommer snart)
#NEW
==Emacs==
En texteditor som är många programmerares favorit.
Speciellt lämpligt för att skriva programkod i.
Kan öppnas från shellet med kommandot ``emacs``, eller eventuellt från
en meny i "applications" eller motsvarande.
Från shellet:
```
$ emacs MyProgram.hs -- öppna filen MyProgram.hs i emacs-editorn
```
#NEW
==Programspråk i vår utbildningar==
Vi lär ut Haskell först
Senare lär vi Java, C, assembler
Och ännu lägre: datorarkitektur, kretselektronik...
Och ännu högre: matematiska modeller av beräkning
Och bryggan mellan nivåer: **kompilatorer**
#NEW
==Kompilatorn==
Kompilatorn är ett program som automatiskt översätter högnivåspråk
till maskinspråk.
Det är därför programmerarna (oftast) kan hålla sig till högnivåspråk.
Det är därför samma program kan köras på olika sorters datorer.
#NEW
==GHC(i)==
GHC = Glasgow Haskell Compiler
GHCi = GHC Interactive
Vi kommer att
- skriva Haskell-program
- kompilera dem med GHCi
- köra dem på datorn
GHC(i) finns för Linux, Mac, Windows... gratis från
[``www.haskell.org/ghc`` www.haskell.org/ghc]
#NEW
==Ett sätt att använda GHC(i)==
Starta ett GHCi-shell i Unix-shellet och skriva program till prompten
```
$ ghci
Prelude> 2+2
4
Prelude> sum [1 .. 100]
5050
```
Snabbt och effektivt för mycket korta program.
Även för att testa längre program.
#NEW
==Ett annat sätt att använda GHC(i)==
Skriv program i en fil, t.ex. ``MyProgram.hs``, läs in i GHCi, och kör i GHCi
```
Prelude> :l MyProgram.hs
MyProgram> factorial 12
479001600
```
Snabbt för program stora som små, men inte effektivast.
Det vi mest använder resten av kursen. Filen ``MyProgram.hs`` kan se ut så här:
```
factorial n = product [1 .. n]
```
#NEW
==Funktionell programmering==
Haskell är ett **funktionellt programspråk**
Köra ett program = beräkna värdet av en funktion med givna argument
Exempel från matematik:
//f : R -> R//
//f(x) = (x + 1)(x - 1)//
//f(3.1) = 8.61//
(Ungefär) samma exempel i Haskell:
```
f :: Float -> Float
f x = (x + 1) * (x - 1)
MyProgram> f 3.1
8.61
```
#NEW
==Aritmetiska funktioner i Haskell==
Heltal, flyttal: ``Int``, ``Float``
De fyra räknesätten: ``+ - * /``
Potensupphöjning: ``2.7 ^ 6``
Dessa kan kombineras i **uttryck**, där parenteser kan behövas:
```
Prelude> 2 + 3 * 4
14
Prelude> (2 + 3) * 4
20
```
Nu ska vi sitta ner och göra några beräkningar.
#NEW
==Prelude-modulen==
GHCi-prompten visar den **modul** vars funktioner är tillgängliga.
En modul, som heter ``Prelude`` är alltid tillgänglig.
Även om man har laddat in ett annat program, är ``Prelude`` tillgänglig.
``Prelude`` innehåller de flesta funktioner vi behöver på denna kurs, t.ex.
de viktigaste matematiska funktionerna.
#NEW
==Listor==
Hur definierar vi medelvärdet av en lista av tal?
Just det: vi behöver en **lista** av tal.
Listor kan skrivas på olika sätt:
```
[]
[1,2,3}
[1 .. 100]
[2,4 .. 100]
```
Preludfunktionen ``sum`` tar en lista av tal och returnerar
deras summa. Nu:
```
Prelude> sum [1,2,3] / 3
2.0
Prelude> sum [1 .. 100] / 100
50.5
```
#NEW
==Oändliga listor==
En lista kan vara oändlig.
```
Prelude> [1 ..]
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,
23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,
42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57Interrupted.
```
Tryck Control-C för att avbryta beräkningen!
Kan vi beräkna summan av en oändlig lista?
```
Prelude> sum [1 ..]
Prelude> sum [0,0 ..]
```
Dags att sitta ner och experimentera igen.
#NEW
==Val från en lista==
Hur skriver vi listan av jämna tal mellan 1 och 100?
Antingen med med stegning:
```
[2,4 .. 100]
```
eller också med en **listkomprehension**:
```
[x | x <- [1 .. 100], even x]
```
Delarna i listkomprehensionen:
- resulterande element: ``x``
- **generator**: ``x <- [1 .. 100]``
- **villkor**: ``even x``
Obs. ``even`` är en funktion som avgör om ett tal är jämnt. Den returnerar
``True`` eller ``False``.
#NEW
==Mera val från en lista==
Vi ska sitta ner och prova exempel:
- listan av alla tal som är udda (``odd``)
- listan av alla tal som är mindre än (``<``) 50
- listan av alla tal vars kvadrat är mindre än 200
- listan av alla tal som är lika med (``==``) sig själva
#NEW
=='Och' och 'eller'==
Villkor kan kombineras med ``&&`` ("och") och ``||`` ("eller").
Listan av tal som är mindre än 10 eller större är 90:
```
[x | x <- [1 .. 100], x < 10 || x > 90]
```
#NEW
==Hur många?==
Funktionen ``length`` anger en listas **längd** som heltal.
```
Prelude> length []
0
Prelude> length [2,4 .. 100]
50
Prelude> length [1,1,1]
3
```
Observera att ``length`` räknar varje etta separat i det tredje exemplet.
Hur många tal uder 100 har kvadrat mindre än 500?
```
length [x | x <- [1 .. 100], x * x < 500]
```
#NEW
==Ändra resultatet i listkomprehension==
Ta en lista av tal och addera 1 till varje tal;
```
[x + 1 | x <- [1 .. 100]]
```
Ta en lista av tal returnera talens kvadrater:
```
[x * x | x <- [1 .. 100]]
```
Ta en lista av tal och returnera talens fakulteter:
```
[product [1 .. x] | x <- [1 .. 20]]
```
Ta en lista av tal returnera kvadraterna av dem som är udda:
```
[x * x | x <- [1 .. 100], odd x]
```
Nu ska vi verkligen sitta ner och experimentera!
#NEW
==Klipp av en lista==
Man kan "klippa av" början av en lista, även oändlig, med ``take``:
```
take 5 [1 ..] == [1,2,3,4,5]
take 5 [1,2,3] == [1,2,3]
```
Med detta kan man skapa **approximeringar** av en oändlig lista:
```
Prelude> take 10 [1/n | n <- [1 ..]]
[1.0,0.5,0.3333333333333333,0.25,0.2,0.16666666666666666,
0.14285714285714285,0.125,0.1111111111111111,0.1]
```
#NEW
==Par och tabeller==
Listor är en **datastruktur**: en komplex form av data (jämfört med
tal, som är enkla).
En annan datastruktur är **par**
```
(1,2)
```
En **tabell** är en lista av par. Här är en tabell av kvadrater:
```
[(x, x * x) | x <- [1 .. 100]]
```
Och, lite mer intressant: av kvadratrötter:
```
[(x, sqrt x) | x <- [1 .. 100]]
```
Låt oss köra några till exempel igen.
#NEW
==Delbarhet och faktorering==
När ett heltal delas med ett heltal, kan man få kvoten med funktionen
``div`` och resten med ``mod``:
```
Prelude> div 13 5
2
Prelude> mod 13 5
3
```
Att ett tal //m// är **delbart** med //n// betyder att
```
mod m n == 0
```
Ett tals **faktorer** är alla de tal som det är delbart med:
```
[n | n <- [1 .. m], mod m n == 0]
Prelude> [n | n <- [1 .. 123], mod 123 n == 0]
[1,3,41,123]
```
Ett **primtal** har inga andra faktorer än 1 och sig självt. Hur ska
vi uttrycka detta i Haskell? Låt oss prova!
#NEW
==Ett delbarhetsbibliotek==
Beräkna alla primfaktorer av talet 45678.
Det här blir risigt, även med listkomprehensioner.
Nu är det dags att skriva ett litet **bibliotek**, en fil med
användbara funktioner som har att göra med delbarhet:
```
module Prime where
divisible m n = mod m n == 0
factors m = [n | n <- [1 .. m], divisible m n]
prime m = m > 1 && factors m == [1,m]
primeFactors m = [n | n <- factors m, prime n]
```
#NEW
==Primtest och faktortabellen==
Vi laddar vårt bibliotek i GHCi:
```
Prelude> :l Prime.hs
Prime> primeFactors 45678
[2,3,23,331]
```
Ny uppgift: skriv ut tabellen av alla tal från 1 till 1000 och
deras primfaktorer.
```
Prime> [(x,primeFactors x) | x <- [1 .. 1000]]
[(1,[]),(2,[2]),(3,[3]),(4,[2]),(5,[5]),(6,[2,3]),(7,[7]),
(8,[2]),(9,[3]),(10,[2,5]),(11,[11]),(12,[2,3]),(13,[13]),
(14,[2,7]),(15,[3,5]),(16,[2]) ...
```
Obs: vår algoritm för att räkna primfaktorer är långsam: senare kurser ska
lära ut bättre algoritmer!
#NEW
==Delbarhetsbiblioteket med typer==
För att dokumentera vad funktionerna gör anger man med fördel
**typsignaturer** till varje funktion:
```
module Prime where
divisible :: Int -> Int -> Bool
divisible m n = mod m n == 0
factors :: Int -> [Int]
factors m = [n | n <- [1 .. m], divisible m n]
prime :: Int -> Bool
prime m = m > 1 && factors m == [1,m]
primeFactors :: Int -> [Int]
primeFactors m = [n | n <- factors m, prime n]
```
#NEW
==Tvillingprimtal==
Konjektur: Det finns oändligt många //p// sådana att både //p// och
//p+2// är primtal. T.ex. 3,5 ; 5,7 ; 11,13 ; 17,19 ; ...
Detta har varken bevisats eller motbevisats.
Uppgift: Skriv ett Haskell-program som genererar (den oändliga?) listan av
alla tvillingprimtal.
#NEW
==Uppgifter==
===Format===
Uppgifterna ska redovisas i en fil ``Ex1.hs``, som ser ut så här:
```
module Main where
import Prime
main = do
print ex2
print ex3
print ex4
print ex5
-- definitionerna av ex2, ex3, 3x4, ex5, samt eventuella hjälpfunktioner
```
När man kör kommandot
```
runghc Ex1
```
skrivs lösningarna på skärmen, rad för rad.
Hur ``print`` och ``do`` exakt fungerar kommer att förklaras
i Föreläsning 3.
#NEW
===Uppgifterna===
1. Skriv och beräkna ett Haskell-uttryck som anger antalet dagar sedan du föddes.
2. Definiera ett Haskell-uttryck ``ex2``, som genererar tabellen av
konverteringar från Fahrenheit till Celsius för Fahrenheit-värdena
0,20,40,...,300 (20 graders stegning). Konversionsformeln är:
C = 5(F-32)/9. T.ex. om F=86 är C=30.
3. Hur många primtal finns mellan 0 och 1000 respektive 7000 och 8000?
Definiera ett uttryck ``ex3``, som returnerar dessa som ett par.
Du får använda filen [``Prime.hs`` Prime.hs] som hjälp.
4. Definiera ett Haskell-uttryck ``twins``, som genererar
(den oändliga?) tabellen av
alla tvillingprimtal. Du får använda filen [``Prime.hs`` Prime.hs]
som hjälp. Definiera sedan ett uttryck ``ex4``, som ger de tio första
paren.
5. Skriv en funktion ``geom``, som approximerar den **geometriska serien**
```
1 + 1/2 + 1/4 + 1/8 + ... + 1/(2^n) + ...
```
med ett heltal ``n`` som argument. Skriv sedan ett uttryck ``ex5``, som ger
listan av approksimationerna med ``n = 1,...,10``.
#NEW
==Sammanfattning och referens==
===GHCi = Glasgow Haskell Compiler interactive===
Starta GHCi med kommandot ``ghci``
Beräkna värdet av ett uttryck: skriv uttrycket i prompten
Ladda en fil: ``:l FILE``
Help: ``:?``
Avbryta beräkning: Control-C
Föregående kommando: pil-upp
===Haskell-filer===
**Module-header** följd av eventuella **modulimportdirektiv**
följda av **funktionsdefinitioner** med eller utan
**typsignaturer**:
```
module Prime where
import List
divisible :: Int -> Int -> Bool
divisible m n = mod m n == 0
-- ingen typsignatur (detta är en kommentar)
factors m = [n | n <- [1 .. m], divisible m n]
```
Modulen ``Prime`` ska finnas i filen ``Prime.hs``.
Undantag: om modulen heter ``Main`` kan filen heta vad som helst.
Varje definition ska börja från början av en rad. Inget annat
får placeras i början av en rad (förutom kommentarer).
Det finns måga sätt att skapa och modifiera en fil under Unix och
andra operativsystem. De flesta dataloger använder **Emacs**.
Den kan startas från Unix-shellen med kommandot ``emacs``.
Då öppnas ett fönster med menyer för att skapa, öppna och spara filer, osv.
===Typer===
Numeriska typer:
- heltal: ``Int``, med positiva och negativa heltal
- flyttal ("reella tal"): ``Float``
Sanningsvärden: ``Bool``, med objekten ``True`` och ``False``
Datastrukturer:
- listor: ``[a]`` där ``a`` är en typ
- par: ``(a,b)``, där ``a`` och ``b`` är typer
Funktioner: ``a -> b`` där ``a`` och ``b`` är typer
- flerställiga funktioner skrivs som ``a -> b -> c``
===Uttryck===
**Infixoperatorer**, med parenteser vid behov: ``(2 + 3) * 4 > 15``
**Funktionsapplikationer**: ``divisible 12 4``
Listor:
- **listning**: ``[1,2,3]``
- **range**: ``[1 .. 100]``, ``[1 ..]``, ``[1,3 .. 100]``
- **listkomprehension**: ``[x * x | x <- [1 .. 100], even x]``
===Preludfunktioner===
```
-- defined for Numeric types
(+) :: (Num a) => a -> a -> a
(-) :: (Num a) => a -> a -> a
(*) :: (Num a) => a -> a -> a
(/) :: (Num a) => a -> a -> a
(^) :: (Num a) => a -> Int -> a -- a^n är a upphöjt till potens n
div :: Int -> Int -> Int
mod :: Int -> Int -> Int
sqrt :: Float -> Float
-- defined for types with Equality
(==) :: (Eq a) => a -> a -> Bool
(/=) :: (Eq a) => a -> a -> Bool
(<) :: (Eq a) => a -> a -> Bool
(>) :: (Eq a) => a -> a -> Bool
(&&) :: Bool -> Bool -> Bool
(||) :: Bool -> Bool -> Bool
even :: Int -> Bool
odd :: Int -> Bool
sum :: (Num a) => [a] -> a
product :: (Num a) => [a] -> a
length :: [a] -> Int
take :: Int -> [a] -> [a]
```