veel defineerimata t¨u¨up). Sageli oleks vaja, et funktsiooni argumendiks sobik-
sid k˜oik teatud tingimustele vastavad t¨u¨ubid, ka need, mida ei ole funktsiooni
defineerimise skoobis veel olemas. Selliseks tingimuseks v˜oib olla n¨aiteks m˜o-
ne teise funktsiooni rakendatavus antud t¨u¨upi v¨a¨artustele.
N¨aiteks v˜oime defineerida pol¨umorfse v˜orduse kontrollimise funktsiooni
(==) ning seej¨arel seda kasutava mittev˜orduse kontrollimise funktsiooni (!=),
mis on rakendatav sama t¨u¨upi v¨a¨artusele nagu funktsioon (==). Kui me n¨u¨ud
mingis alamskoobis funktsiooni (==) definitsiooni laiendame, nii et see on
rakendatav mingit uut t¨u¨upi v¨a¨artustele, siis tavalise ad-hoc-pol¨umorfismi
korral funktsioon (!=) j¨a¨ab kasutama vana (==) definitsiooni ning ei ole
rakendatav uut t¨u¨upi v¨a¨artustele. Tegelikult me sooviks, et (==) definitsioo-
ni uuendamisel uueneks automaatselt ka (!=) v¨a¨artus, st ¨uhe funktsiooni
definitsioon kasutaks parameetrina teise funktsiooni v¨a¨artust selle esimese
funktsiooni v¨aljakutsumise hetkel ehk d¨unaamilises skoobis.
Seega tekib vajadus teatud d¨unaamilise skoopimise elementide j¨arele.
Funktsiooni definitsioonis oleks vaja kasutada lisaks leksilise skoobi identifi-
kaatoritele ka m˜onda d¨unaamilise skoobi identifikaatorit. ¨
Uks v˜oimalus selle
realiseerimiseks oleks panna funktsiooni semantika s˜oltuma lisaks leksilise
skoobi keskkonnale ka d¨unaamilise skoobi keskkonnast ning eristada kuida-
gi s¨untaktiliselt, kas identifikaator viitab leksilise v˜oi d¨unaamilise keskkonna
muutujale. Samas ei ole funktsiooni defineerimise hetkel teada, millised on
selles definitsioonis kasutatavate d¨unaamilise keskkonna muutujate t¨u¨ubid
funktsiooni v¨aljakutsumise skoobis. Seega tuleks kasutatavate d¨unaamilise
skoopimisega muutujate t¨u¨ubid kuidagi deklareerida.
6.3.2
D¨
unaamilise skoopimise elemendid Haskellis
GHC-s on d¨unaamilise skoopimise jaoks v˜oimalik kasutada implitsiitseid pa-
rameetreid ([2], jaotis 8.7.2):
double :: (?single :: Integer) => Integer
double = 2 * ?single
xs = (let ?single = 3 in double, let ?single = 4 in double)
Siin xs saab v¨a¨artuseks (6,8). N¨aeme, et implitsiitse parameetri ?single
t¨u¨up Integer on fikseeritud.
Selles n¨aites funktsioonil double ainult implitsiitne parameeter ongi ja
tavalist argumenti ei ole. Sageli on aga funktsioonil olemas ka tavaline ar-
gument ja implitsiitne parameeter s˜oltub selle tavalise argumendi t¨u¨ubist.
Eespool vaadeldud funktsioon (!=) korral oleks implitsiitseks parameetriks
funktsiooni (==) (monomorfne) realisatsioon funktsioonile (!=) argumendiks
antud v¨a¨artuse t¨u¨ubi jaoks.
42
Haskellis on selleks olemas t¨u¨ubiklassid. N¨aiteks v˜oime defineerida
class Equal a where
(===) :: a -> a -> Bool
(!=) :: Equal a => a -> a -> Bool
x != y = not (x === y)
Siin on (==) asemel kasutatud (===), kuna esimene on prel¨u¨udis defineeritud
ja Haskell ei luba peatasemel muutujaid ¨umber defineerida. Siin funktsiooni
(!=) implitsiitseks parameetriks on funktsiooni (===) monomorfne realisat-
sioon t¨u¨ubi a jaoks. T¨u¨up a selgub funktsioonile (!=) esimese argumen-
di andmisel, sel hetkel kehtivast skoobist v˜oetakse ka (===) realisatsioon,
mis funktsioonile (!=) antakse. Funktsiooni (!=) t¨u¨up sisaldab tingimust
Equal a, mis m¨a¨arab, et see funktsioon on rakendatav k˜oikidele t¨u¨upidele
a, mis rahuldavad predikaati Equal (ehk millele on rakendatav funktsioon
(===).
6.3.3
D¨
unaamilise skoopimise elemendid Fumontrixis
Fumontrixis on samuti olemas t¨u¨ubiklassid. Defineerime klassi Equal ja selle
eksemplari t¨aisarvut¨u¨ubi jaoks:
class equal forall A. A -> A -> Bool;
type equal = \ a .
case a of
Int -> value intEq;
end;
Fumontrixis on t¨u¨ubiklasside esindajad m¨a¨aratud t¨u¨ubitaseme funktsiooni-
ga, mille nimi ¨uhtib klassi nimega ja mis seab t¨u¨ubile vastavusse monomorfse
v¨a¨artuse (klassi eksemplari), mis on pol¨umorfse v¨a¨artuse realisatsioon an-
tud t¨u¨ubiparameetri v¨a¨artuse jaoks. Kui mingis alamskoobis on vaja klassi
esindajaid lisada v˜oi muuta, siis tuleb lihtsalt vastav t¨u¨ubitaseme funktsioon
¨umber defineerida. Lisame n¨aiteks eksemplari t˜oev¨a¨artust¨u¨ubi jaoks:
type equal = \ a .
case a of
Bool -> value boolEq;
_
-> equal a;
end;
43
N¨aidise _ abil s¨ailitame siin ka varem defineeritud eksemplarid.
T¨u¨ubiklassile vastava pol¨umorfse andmetaseme funktsiooni defineerime
j¨argmiselt:
(==) = forall equal A. type equal A;
N¨u¨ud saame defineerida ka mittev˜orduse kontrollimise funktsiooni:
(!=) = forall equal A.
\ x : A . \ y : A .
not (x == y);
Siin ei ole vaja enam t¨u¨ubitaseme funktsiooni equal v¨alja kutsuda, vaid
v˜oime kasutada eelnevalt defineeritud andmetaseme funktsiooni (==). Kvan-
toriga muutuja sissetoomisel tuleb vaid lisada kitsendus equal, mis n˜ouab,
et muutuja kuuluks sellesse klassi.
Fumontrixis on olemas ainult ¨uhe argumendiga t¨u¨ubiklassid, kitsendada
saab ainult kvantifitseeritavat muutujat (mitte seda parameetrina sisaldavat
t¨u¨upi) ning ¨uhele muutujale saab lisada ainult ¨uhe kitsenduse. Seega v˜orrel-
des Haskelli ja eriti GHC-ga on siin tegemist ¨usna lihtsa t¨u¨ubiklasside reali-
satsiooniga. Fumontrixis on p˜ohir˜ohk asetatud t¨u¨ubitaseme funktsioonidele,
mis sellistel juhtudel, kus d¨unaamilist skoopimist vaja ei l¨ahe, on palju suure-
mate v˜oimalustega kui GHC analoogilised konstruktsioonid. Seda vaatlesime
l¨ahemalt peat¨ukis 5.
6.3.4
D¨
unaamilise skoopimise elemendid ja objektorienteeritus
Ka objektorienteeritud keeltes esineb selline d¨unaamilise skoopimisega seo-
tud pol¨umorfism. N¨aiteks Javas v˜oime eelmistes jaotistes vaadeldud n¨aite
analoogina defineerida abstraktse klassi ja seda realiseeriva mitteabstraktse
klassi:
abstract class Equal {
abstract boolean equal(Equal other);
boolean notequal(Equal other) {
return !equal(other);
}
}
class MyInt extends Equal {
int x;
44