public boolean equal(Equal other) {
return x == ((MyInt) other).x;
}
}
Siin abstraktse funktsiooni equal definitsioon s˜oltub konkreetsest klassi Equal
alamklassist, kuid funktsioon notequal defineeritakse selle kaudu juba ¨ulem-
klassis. Selle alamklassi funktsiooni equal realisatsioon antakse implitsiitse
parameetrina (nn this-argumendi koosseisus) funktsioonile notequal sel-
le v¨aljakutsumisel. Alamklassi definitsioon ei pea olema ¨ulemklassi definee-
rimisel k¨attesaadav, implitsiitse parameetri v¨a¨artus v˜oetakse d¨unaamilisest
skoobist.
6.4
Pol¨
umorfsed v¨
a¨
artused funktsiooni argumendina
6.4.1
Pol¨
umorfsed v¨
a¨
artused
Seni vaatlesime pol¨umorfismi funktsioonide jaoks, mis v˜oivad argumendiks
v˜otta erinevat t¨u¨upi v¨a¨artusi ning k¨aituda nende korral kas ¨uhtemoodi v˜oi
erinevalt. Pol¨umorfsed v˜oivad aga lisaks funktsioonidele olla ka mittefunktsio-
naalsed v¨a¨artused, mis samuti v˜oivad olla erinevate t¨u¨upide korral kas samal
v˜oi erineval sisemisel kujul. Neid v¨a¨artusi on vastavalt vajadusele v˜oimalik
kasutada erinevat t¨u¨upi v¨a¨artustena.
Pol¨umorfsete funktsioonide korral saab funktsiooni k¨aitumise ja tulemuse
t¨u¨ubi m¨a¨arata (monomorfse) argumendi t¨u¨ubi p˜ohjal. Pol¨umorfsete v¨a¨artuste
korral saab nende t¨u¨ubi m¨a¨arata selle (monomorfse) funktsiooni deklareeri-
tud argumendi t¨u¨ubi j¨argi, millele see v¨a¨artus argumendiks antakse.
Seega kui pol¨umorfne on ainult funktsioon v˜oi ainult argument, kuid mitte
m˜olemad, siis ei teki probleeme argumendile monomorfse t¨u¨ubi m¨a¨aramise-
ga ja seej¨arel tulemuse t¨u¨ubi m¨a¨aramisega, kuna see monomorfne t¨u¨up on
¨uheselt m¨a¨aratud (eeldusel, et vaadeldav pol¨umorfne t¨u¨up vaadeldava mono-
morfse t¨u¨ubiga ¨uldse koosk˜olas on).
Probleem tekib siis, kui pol¨umorfsed on nii funktsioon kui sellele argu-
mendiks antud v¨a¨artus. Siis ei pruugi tulemuse t¨u¨up enam ¨uheselt m¨a¨ara-
tud olla. Kui funktsioonile Fumontrixi t¨u¨upi forall A. Pair A Int -> A
anda argument t¨u¨upi forall B. Pair Bool B, siis on tulemuse t¨u¨up Bool
veel ¨uheselt m¨a¨aratud. Kui aga funktsioonile t¨u¨upi forall A. A -> List A
anda argument t¨u¨upi forall B. List B, siis v˜oib tulemus olla nii t¨u¨upi
forall B. List (List B) (kui v¨a¨artustatakse A = List B) kui ka
List (forall B. List B) (kui v¨a¨artustatakse A = forall B. List B).
See probleem tekib sellisel juhul, kui funktsiooni t¨u¨ubis on argumendi
koha peal (kontravariantses positsioonis) ainult t¨u¨ubimuutuja, mis on selle
45
funktsiooni t¨u¨ubi tipmisel tasemel kvantoriga seotud. Seda t¨u¨ubimuutujat
on v˜oimalik unifitseerida iga t¨u¨ubiga ja seega juhul, kui argumendiks antud
v¨a¨artuse t¨u¨up sisaldab tipmisel tasemel kvantoreid, siis on v˜oimalik ¨uks k˜oik
mitu nendest kvantoritest avada (kas k˜oik, m˜oned v˜oi mitte ¨uhtegi) enne
unifitseerimist. Avamata kvantorid l¨ahevad tulemuse t¨u¨ubi ette.
Kui funktsiooni t¨u¨ubis argumendi koha peal on midagi muud kui ainult
t¨u¨ubimuutuja, siis seda probleemi ei teki. Kui seal on tipmisel tasemel konst-
ruktor (v˜oi olemasolukvantor), siis tuleb igal juhul argumendiks antava v¨a¨ar-
tuse k˜oik tipmised ¨uldisuskvantorid avada, et unifitseerimine v˜oimalik oleks.
Kui seal on tipmisel tasemel ¨uldisuskvantor, siis tuleb argumendis antavas
v¨a¨artuses avada nii palju kvantoreid, et avamata j¨a¨anud tipmiste kvantorite
arv saaks v˜ordseks funktsiooni t¨u¨ubis argumendi koha peal olevate tipmiste
kvantorite arvuga.
6.4.2
Impredikatiivne pol¨
umorfism
Eelmises alajaotises vaadeldud probleemi v¨altimiseks on Haskell 98-s keela-
tud impredikatiivne pol¨umorfism. Impredikatiivne pol¨umorfism v˜oimaldab
kvantifitseeritud t¨u¨ubimuutuja v¨a¨artustada pol¨umorfse t¨u¨ubiga. Seega Has-
kell 98-s v¨a¨artustatakse eelnevas n¨aites A = List B ja kvantorid j¨a¨avad alati
tipmisele tasemele.
Ka GHC-s ja Fumontrixis valitakse selles n¨aites sama v¨a¨artustus, kuid
siin on v˜oimalik teatud juhtudel ka impredikatiivsust kasutada (GHC impre-
dikatiivsuse kohta vt [2], jaotis 8.7.5). Defineerime n¨aiteks GHC-s
f1 :: forall a. a -> [a]
f1 = undefined
v2 :: forall b. [b]
v2 = undefined
Siis f1 v2 on t¨u¨upi forall b. [[b]], aga
(f1 :: (forall b. [b]) -> [forall b. [b]]) v2
annab tulemuse t¨u¨ubiks [forall b. [b]], kuna siin v¨a¨artustatakse f1 t¨u¨u-
bis muutuja a ilmutatult t¨u¨ubiga forall b. [b]. Pol¨umorfse v¨a¨artuse t¨u¨u-
bis t¨u¨ubimuutuja ilmutatud v¨a¨artustamine on GHC-s kohmakas, kuna sel-
leks tuleb kogu v¨a¨artuse t¨u¨up ¨umber kirjutada ja asendada seal muutuja k˜oik
esinemised selle soovitava t¨u¨ubiga. Selleks, et seda soovitavat t¨u¨upi ei peaks
mitu korda v¨alja kirjutama, v˜oiks defineerida t¨u¨ubis¨unon¨u¨umi:
type T1 = forall b. [b]
ja siis kasutada
46
(f1 :: T1 -> [T1]) f2
Samas saab GHC-s t¨u¨ubis¨unon¨u¨umi defineerida ainult peataseme skoobis
ning, kui seda t¨u¨ubimuutuja v¨a¨artustamist on vaja teha kuskil s¨ugavas alam-
skoobis, siis j¨a¨ab kood hakituks. Samuti on vaja selle pol¨umorfse v¨a¨artuse
t¨u¨ubi struktuur ¨umber kirjutada ning see struktuur v˜oib m˜onikord olla v¨aga
keeruline.
Fumontrixis v˜oime defineerida
f1 = bottom $: (forall A. A -> List A);
v2 = bottom $: (forall B. List B);
Siis f1 v2 on t¨u¨upi forall B. List (List B), aga
f1 $: (forall B. List B) v2
on t¨u¨upi List (forall B. List B). Operaator $: avab tipmise taseme
¨uldisuskvantori ja v¨a¨artustab sellega seotud muutuja antud t¨u¨ubiga, seega
erinevalt GHC-st ei pea Fumontrixis kogu v¨a¨artuse t¨u¨upi ¨umber kirjutama,
vaja on kirjutatada vaid see t¨u¨up, millega muutuja v¨a¨artustatakse. Fumon-
trixis v˜oime kasutada ka typeof-operaatorit ja kirjutada viimase n¨aitega
samav¨a¨arse
f1 $: (typeof v2) v2
Kui me ei soovi argumenti kaks korda v¨alja kirjutada (see v˜oib olla n¨aiteks
mingi keeruline avaldis), siis v˜oime defineerida eraldi funktsiooni rakendamise
operaatori t¨u¨ubitaseme funktsioonina:
type applyImpred = \ f : @ . \ x : @ .
value (type f) $: (typeof type x) (type x);
ja siis kasutada
type applyImpred (value f1) (value v2)
Operaator applyImpred on kasutatav sel juhul, kui funktsiooni t¨u¨ubis argu-
mendi kohal on t¨u¨ubimuutuja, mis on seotud selle funktsiooni t¨u¨ubis k˜oige
tipmisel tasemel asuva ¨uldisuskvantoriga.
Impredikatiivne pol¨umorfism v˜oib esineda ka sel juhul, kui t¨u¨ubimuutuja
ei esine funktsiooni t¨u¨ubis otse argumendi kohal, vaid on seal n¨aiteks mingi
konstruktori parameetriks. N¨aiteks GHC-s
f3 :: forall a. [a] -> [a]
f3 = undefined
v4 :: [forall b. [b]]
v4 = undefined
47
Dostları ilə paylaş: |