Programmierkurs II

Werbung
Programmierkurs II
Mengen – ein weiteres Beispiel
• DatentypfürLambda-Ausdrücke
data LExpr
= Var String
| App LExpr LExpr
| Lam String LExpr
deriving (Eq, Show)
LambdaAusdrücke- Übungsaufgabe
• UnterschiedlicheLambdaAusdrücke
1. q
2. x
3. \x. x y
4. \f x y. f y y
5. \x z. y (\x. x y) (\y. x y)
LambdaAusdrücke- Übungsaufgabe
• UnterschiedlicheLambdaAusdrücke
e1
e2
e3
e4
=
=
=
=
Var "q"
Var "x"
Lam "x" (App (Var "x") (Var "y"))
Lam "f" (Lam "x" (Lam "y"
(App (App (Var "f") (Var "y")) (Var "x"))))
e5 = Lam "x" . Lam "z"
$ Var "y"
`App` (Lam "x" $ Var "x" `App` Var "y")
`App` (Lam "y" $ Var "x" `App` Var "y")
LambdaAusdrücke- Übungsaufgabe
AllefreienVariablenfinden:
free
free
free
free
:: LExpr -> MySet String
(Var v)
= singleton v
(App e e') = free e # free e'
(Lam v e) = delete v $ free e
Test:
*Main> free $ Lam "x" (App (Var "x") (Var "y"))
{"y"}
FreieVariablen- Mengen
AllefreienVariablenfinden:
free
free
free
free
:: LExpr -> MySet String
(Var v)
= singleton v Vereinigung
(App e e') = free e # free e'
(Lam v e) = delete v $ free e
Test:
*Main> free $ Lam "x" (App (Var "x") (Var "y"))
{"y"}
FreieVariablen- Mengen
AllegebundenenVariablenfinden:
bound :: LExpr -> MySet String
bound (Var _)
= Empty
bound (App e1 e2) = bound e1 # bound e2
bound (Lam v e)
| element v $ free e = insert v $ bound e
| otherwise
= bound e
Test:
*Main> bound $ Lam "x" (App (Var "x") (Var "y"))
{"x"}
FreieVariablen- Mengen
MusseineAlphakonversiondurchgeführtwerden?
ImplementiertaufListen:
safeList :: LExpr -> LExpr -> Bool
safeList e1 e2 = null [ v | v <- boundList e1,
v `elem` freeList e2 ]
Alpha-Konversion- Beispiel
MusseineAlphakonversiondurchgeführtwerden?
ImplementiertaufListen:
safeList :: LExpr -> LExpr -> Bool
safeList e1 e2 = null [ v | v <- boundList e1,
v `elem` freeList e2 ]
ImplementiertaufMengen:
safe :: LExpr -> LExpr -> Bool
safe e1 e2 = isEmpty $ (bound e1) % (free e2)
Alpha-Konversion- Beispiel
Programmierkurs II
Typklassen
• EinigeTypklassenhabenwirschonkennengelernt
– Eq,Ord,...
• MankönnteTypklassenalsPendantzuInterfacesin
objektorientiertenSprachen(e.g.,Java)bezeichnen.
– EsmüssendiejeweiligenbereitgestelltenFunktionen
ausimplementiertwerden.
– DieseImplementierungenkönnensichunterscheiden.
– EinDatentypkannmehrereTypklassenimplementieren.
Typklassen
SchauenwirunsmalkurzJavaScriptan:
if(0){ console.log("YEAH!");}
else { console.log("NO!");}
if(""){ console.log("YEAH!");}
else { console.log("NO!");}
if(“String"){ console.log("YEAH!");}
else { console.log("NO!");}
...
Typklassen
WirwollendiesesVerhalteninHaskell simulieren:
class YesNo a where
yesno :: a -> Bool
Typklassen
WirwollendiesesVerhalteninHaskell simulieren:
class YesNo a where
yesno :: a -> Bool
StringsalsInstanzvonYesNo definieren:
instance YesNo [a] where
yesno [] = False
yesno _ = True
Typklassen
Maybe alsInstanzvonYesNo definieren:
instance YesNo (Maybe a) where
yesno (Just _) = True
yesno Nothing = False
UnsereMengenalsInstanzvonYesNo definieren:
instance YesNo (MySet a) where
yesno Empty = False
yesno _
= True
Typklassen
Testen:
*Main>
True
*Main>
False
*Main>
True
*Main>
False
*Main>
True
*Main>
False
*Main>
False
*Main>
True
yesno "Hallo"
yesno ""
yesno [1,2]
yesno []
yesno $ Just 10
yesno $ Nothing
yesno Empty
yesno $ 1:<:Empty
Typklassen
Funktion,welchedieJavaScriptif-Anweisungsimuliert:
yesnoIf :: (YesNo y) => y -> a -> a -> a yesnoIf
yesnoVal yesResult noResult = if yesno yesnoVal
then yesResult
else noResult
Ausprobieren:
*Main> yesnoIf [] "YEAH!" "NO!"
"NO!"
*Main> yesnoIf "Yes" "YEAH!" "NO!"
"YEAH!"
*Main> yesnoIf (Just 302) "YEAH!" "NO!"
"YEAH!"
Typklassen
Programmierkurs II
Module
• DiePrelude umfassteinengroßenFunktionsumfang,kannaber
durchzusätzlicheModulenocherweitertwerden.
• ModulekönnendabeihelfenselbstgeschriebenenCodebesser
zustrukturieren.
• GenerischerCodekanndadurchinvielenunterschiedlichen
Programmenverwendetwerden.
Module- Motivation
• BisherhabenwirlediglichmitFunktionenausderPrelude
gearbeitet.
• EsgibtaberModule
– ZurListenverarbeitung
– ZumparallelenProgrammieren
– ZumArbeitenmitCharakter
– ...
• NatürlichschreibenwirselberauchModule
Module- Einleitung
• BevormanFunktionenschreibtmüssenModuleimportiert
werden.
• DeshalbbefindetsichderImportimmeramAnfangdesSkripts.
• NatürlichkönnenmehrereModulegeladenwerden.
• WirbekommendadurchZugriffaufalleexportiertenInhalte.
– Esmussexplizitangegebenwerdenwasexportiertwerdensoll.
– Esmussnichtallesexportiertwerden(z.B.Hilfsfunktionen)
Module- Importieren
ErweiternwirdieFunktionsvielfaltbzgl.Listenverarbeitung:
import Data.List
numUniques :: (Eq a) => [a] -> Int
numUniques = length . nub
Module
ErweiternwirdieFunktionsvielfaltbzgl.Listenverarbeitung:
import Data.List
numUniques :: (Eq a) => [a] -> Int
numUniques = length . nub
Scant eineListeundentferntDuplikate
Module
EinModulkannauchdirektimGHCIgeladenwerden:
Prelude> :m Data.List
Prelude Data.List>
Module
EinModulkannauchdirektimGHCIgeladenwerden:
Prelude> :m Data.List
Prelude Data.List>
Prelude Data.List> nub "hallo"
"halo"
Module
FallsmannichteinganzesModul,sondernnureinpaarwenige
Funktionenbenötigt:
import Data.List (nub, sort)
OdereinganzesModulohnebestimmteFunktionen:
import Data.List hiding (nub)
Module
FallsmannichteinganzesModul,sondernnureinpaarwenige
Funktionenbenötigt:
import Data.List (nub, sort)
OdereinganzesModulohnebestimmteFunktionen:
import Data.List hiding (nub)
Module
ModuleimportierengleichnamigeFunktionen:
import Data.Map
Module– Namenskonflikte
ModuleimportierengleichnamigeFunktionen:
import Data.Map
*Main> :t filter
<interactive>:1:1:
Ambiguous occurrence ‘filter’
It could refer to either ‘Data.List.filter’,
imported from ‘Data.List’ (and originally defined in ‘GHC.List’)
or ‘Data.Map.filter’,
imported from ‘Data.Map’ at modules.hs:7:1-15
(and originally defined in ‘containers-0.5.6.2:Data.Map.Base’)
Module– Namenskonflikte
Lösungdurch„qualified“Import:
import qualified Data.Map as M
Zugriffauffilter:
*Main> :t filter
filter :: (a -> Bool) -> [a] -> [a]
*Main> :t M.filter
M.filter :: (a -> Bool) -> M.Map k a -> M.Map k a
Module– Namenskonflikte
SchauenwirunsmaleinigenützlicheFunktionenan:
*Main> transpose ["hallo", "liebe", "Leute"]
["hlL","aie","leu","lbt","oee"]
Module– Data.List
SchauenwirunsmaleinigenützlicheFunktionenan:
*Main> transpose ["hallo", "liebe", "Leute"]
["hlL","aie","leu","lbt","oee"]
Matrixberechnungen:
*Main> transpose [[1,2,3],[4,5,6],[7,8,9]]
[[1,4,7],[2,5,8],[3,6,9]]
Module– Data.List
Polynomiale Gleichungberechnen:
3x2 +5x+9,10x3 +9,and 8x3 +5x2 +x- 1
Module– Data.List
Polynomiale Gleichungberechnen:
3x2 +5x+9,10x3 +9,and 8x3 +5x2 +x- 1
*Main> transpose [[0,3,5,9],[10,0,0,9],[8,5,1,-1]]
[[0,10,8],[3,0,5],[5,0,1],[9,9,-1]]
*Main> map sum $ transpose [[0,3,5,9],[10,0,0,9],[8,5,1,-1]]
[18,8,6,17]
Module– Data.List
Listensortieren:
*Main> sort [1,2,5,4,3]
[1,2,3,4,5]
*Main> sort "unsorted"
"denorstu"
Listengruppieren:
*Main> group [1,1,1,2,2,3,2,1]
[[1,1,1],[2,2],[3],[2],[1]]
Module– Data.List
Beideskombinieren:
*Main> group . sort $ [1,1,1,2,2,3,2,1]
[[1,1,1,1],[2,2,2],[3]]
WasbewirktdiesesSkript:
*Main> map (\[email protected](x:xs) -> (x,length l)) . group . sort $
[1,1,1,2,2,3,2,1]
Module– Data.List
Beideskombinieren:
*Main> group . sort $ [1,1,1,2,2,3,2,1]
[[1,1,1,1],[2,2,2],[3]]
WasbewirktdiesesSkript:
*Main> map (\[email protected](x:xs) -> (x,length l)) . group . sort $
[1,1,1,2,2,3,2,1]
[(1,4),(2,3),(3,1)]
Module– Data.List
ArbeitenmitStrings!
NeueZeilenseparieren:
*Main> lines "first line\nsecond line\nlast line"
["first line","second line","last line"]
NeueZeileneinfügen:
*Main> unlines ["first line","second line","last line"]
"first line\nsecond line\nlast line\n"
Module– Data.List
ArbeitenmitStrings!
Worteseparieren:
*Main> words "hey these are the words in this sentence"
["hey","these","are","the","words","in","this","sentence"]
NeueZeileneinfügen:
*Main> unwords
["hey","these","are","the","words","in","this","sentence"]
"hey these are the words in this sentence"
Module– Data.List
Modul,welchesFunktionenaufChar exportiert.
*Main>
False
*Main>
True
*Main>
True
*Main>
False
isLetter '\n'
isControl '\n'
isSpace '\n'
isPrint '\n'
*Main>
False
*Main>
False
*Main>
True
*Main>
True
isLetter '€'
isControl '€'
isSymbol '€'
isPrint '€'
*Main>
True
*Main>
False
*Main>
True
*Main>
True
isLetter 'Z'
isControl 'Z'
isUpper 'Z'
isPrint 'Z'
EsgibtnochsehrvieleweiterePrädikatederForm:Char -> Bool
Module– Data.Char
ÜberprüfenobBenutzernamegültigist:
*Main> isAlphaNum 'Z'
True
*Main> isAlphaNum '1'
True
*Main> isAlphaNum '?'
False
Module– Data.Char
ÜberprüfenobBenutzernamegültigist:
*Main>
True
*Main>
True
*Main>
False
*Main>
True
*Main>
False
isAlphaNum 'Z'
isAlphaNum '1'
isAlphaNum '?'
all isAlphaNum "bobby283"
all isAlphaNum "bobby!283"
Module– Data.Char
NützlicheInformationenzuChar:
*Main> generalCategory
LowercaseLetter
*Main> generalCategory
Space
*Main> generalCategory
OtherPunctuation
*Main> generalCategory
DecimalNumber
'a'
' '
'.'
'2'
Esgibtca.31Kategorien.
Module– Data.Char
NützlicheInformationenzuChar:
*Main> map generalCategory " \t\nA9?|"
[Space,Control,Control,UppercaseLetter,DecimalNumber,OtherPunctuation,
MathSymbol]
Module– Data.Char
NützlicheInformationenzuChar:
*Main> map generalCategory " \t\nA9?|"
[Space,Control,Control,UppercaseLetter,DecimalNumber,OtherPunctuation,
MathSymbol]
Überprüfen,oballesinGroßbuchstabengeschriebenwurde:
*Main> all (==UppercaseLetter) $ map generalCategory " \t\nA9?|"
False
*Main> all (==UppercaseLetter) $ map generalCategory "SILENCE"
True
Module– Data.Char
Char indiedazugehörigeDezimaldarstellungüberführen:
*Main> ord 'A'
65
*Main> ord ‘a'
97
*Main> chr 65
'A'
Module– Data.Char
PrimitiveVerschlüsselungeinesStrings
encode :: Int -> String -> String
encode shift msg =
let ords = map ord msg
shifted = map (+ shift) ords
in map chr shifted
decode :: Int -> String -> String
decode shift msg = encode (negate shift) msg
Module– Data.Char
PrimitiveVerschlüsselungeinesStrings
*Main> encode 0 "das kann man nicht lesen"
"das kann man nicht lesen"
*Main> encode 1 "das kann man nicht lesen"
"ebt!lboo!nbo!ojdiu!mftfo"
*Main> decode 1 "ebt!lboo!nbo!ojdiu!mftfo"
"das kann man nicht lesen"
Module– Data.Char
• EsfindensichauchunterschiedlicheDatenstrukturenals
Module.
• BeimArbeitenmitWertepaaren(Identifier,Value)kanndas
Data.Map Modulhilfreichsein.
– OrganisiertdieDatenstrukturineinemBaum(schnellererZugriffals
Listen)
– StelltvielenützlicheFunktionenautomatischschonbereit
Module– Data.Map
Initialisierung:
import qualified Data.Map as Map
mapData = Map.insert 5 600 (Map.insert 4 200
( Map.insert 3 100 Map.empty))
Schlüsselkönnenüberschriebenwerden:
*Main> Map.insert 3 500 mapData
fromList [(3,500),(4,200),(5,600)]
Module– Data.Map - Beispiel
Map undFilter aufData.Map:
*Main> Map.map (*2) mapData
fromList [(3,200),(4,400),(5,1200)]
*Main> Map.filter (< 500) mapData
fromList [(3,100),(4,200)]
SchlüsselundWerteabfragen:
*Main> Map.keys mapData
[3,4,5]
*Main> Map.elems mapData
[100,200,600]
Module– Data.Map - Beispiel
• MankannauchMengenalsDatenstrukturenimportieren.
• DieFunktionenorientierensichstarkandenvonunsbereits
implementiertenFunktionen.
– Vereinigung
– Schnittmengen
– Teilmengen
– ...
Module– Data.Set
Initialisierung:
import qualified Data.Set as Set
set = Set.fromList text
SchnittmengeundVereinigung
*Main> Set.intersection set set2
fromList " abdehlmnrstuy"
*Main> Set.union set set2
fromList "
!.?BIRTWabcdefghijlmnoprstuvwy"
Module– Data.Set - Beispiel
•
•
•
•
EineMöglichkeitseinenCodezustrukturieren.
ÄhnlicheFunktionengehörenineinModul.
EinModulentsprichteinerDatei.
WennwirModuleimportieren könnenwirnurdieFunktionen
verwenden,welchevondementsprechendenModulexportiert
wurden.
Moduleselbererstellen
ZuBeginndefinierenwirdenNamendesModuls(derDatei):
module Geometry
( sphereVolume
, sphereArea
, cubeVolume
, cubeArea
, cuboidArea
, cuboidVolume )
where
Moduleselbererstellen
ZuBeginndefinierenwirdenNamendesModuls(derDatei)
module Geometry
( sphereVolume
, sphereArea
, cubeVolume
, cubeArea
, cuboidArea
, cuboidVolume )
where
NamenderFunktionen,welcheexportiert
werdensollen.
Moduleselbererstellen
Funktionenausimplementieren:
sphereVolume :: Float -> Float
sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3)
sphereArea :: Float -> Float
sphereArea radius = 4 * pi * (radius ^ 2)
cubeVolume :: Float -> Float
cubeVolume side = cuboidVolume side side side
cubeArea :: Float -> Float
cubeArea side = cuboidArea side side side
cuboidVolume :: Float -> Float -> Float -> Float
cuboidVolume a b c = rectangleArea a b * c
cuboidArea :: Float -> Float -> Float -> Float
cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2
+ rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
Moduleselbererstellen
Funktionenausimplementieren:
sphereVolume :: Float -> Float
sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3)
sphereArea :: Float -> Float
sphereArea radius = 4 * pi * (radius ^ 2)
cubeVolume :: Float -> Float
cubeVolume side = cuboidVolume side side side
cubeArea :: Float -> Float
cubeArea side = cuboidArea side side side
cuboidVolume :: Float -> Float -> Float -> Float
cuboidVolume a b c = rectangleArea a b * c
cuboidArea :: Float -> Float -> Float -> Float
cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2
+ rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
Moduleselbererstellen
Funktionenausimplementieren:
sphereVolume :: Float -> Float
sphereVolume radius = (4.0 / 3.0) * pi * (radius ^ 3)
sphereArea :: Float -> Float
sphereArea radius = 4 * pi * (radius ^ 2)
cubeVolume :: Float -> Float
cubeVolume side = cuboidVolume side side side
cubeArea :: Float -> Float
cubeArea side = cuboidArea side side side
cuboidVolume :: Float -> Float -> Float -> Float
cuboidVolume a b c = rectangleArea a b * c
cuboidArea :: Float -> Float -> Float -> Float
cuboidArea a b c = rectangleArea a b * 2 + rectangleArea a c * 2
+ rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
Moduleselbererstellen
WirkönnenausdenModuleneineHierarchischeStruktur
aufbauen:
module Geometry.Cuboid
( volume , area )
where
volume :: Float -> Float -> Float -> Float
volume a b c = rectangleArea a b * c
area :: Float -> Float -> Float -> Float
area a b c = rectangleArea a b * 2 + rectangleArea a
c * 2 + rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
Moduleselbererstellen
WirkönnenausdenModuleneineHierarchischeStruktur
aufbauen: IndemVerzeichnis‘Geometry‘befindetsichdieDatei‘Cuboid‘
module Geometry.Cuboid
( volume , area )
where
volume :: Float -> Float -> Float -> Float
volume a b c = rectangleArea a b * c
area :: Float -> Float -> Float -> Float
area a b c = rectangleArea a b * 2 + rectangleArea a
c * 2 + rectangleArea c b * 2
rectangleArea :: Float -> Float -> Float
rectangleArea a b = a * b
Moduleselbererstellen
WirkönnenausdenModuleneineHierarchischeStruktur
aufbauen:
module Geometry.Cube
( volume , area )
where
import qualified Geometry.Cuboid as Cuboid
volume :: Float -> Float
volume side = Cuboid.volume side side side
area :: Float -> Float
area side = Cuboid.area side side side
Moduleselbererstellen
Herunterladen