Polimorfizmus

15.1. Kérdés.
Első próbálkozás:
- fun b x = x+1;
> val b = fn : int -> int
Második próbálkozás:
- fun b x = x;
> val 'a b = fn : 'a -> 'a
    ^  
Ide miért jön be az 'a? Vagy inkább úgy kérdezem, van-e lényegbeli különbség az 'a-s és az 'a nélküli típusnál?

A könyv (4. javított kiadás) 53. oldalán fun id x = x-re val id = 'a -> 'a van írva válasznak, ellenben ha beírom mosml-be, akkor ott is megjelenik az 'a (ugyanígy a megfelelő fólián is ki van írva az ''a).

15.1. Válasz.
Hallgató: Az első próbálkozással szemben a második próbálkozás polimorf függvényt definiál, az okot tehát a polimorfizmus kezelésében kell keresni.

Az 'a-t szerintem azért írja ki, hogy mutassa, hogy b egy polimorf (típus-paraméteres) dolog. Mivel ez a típusából amúgy is látszik, én ezt nem tekintem lényegi különbségnek (a val b = fn : 'a -> 'a felíráshoz képest természetesen).

A könyvben valószínűleg azért van másképp, mert az írásakor használt mosml verzió még nem akarta külön is hangsúlyozni, hogy egy függvény polimorf.

Oktató: A függvény definiálásakor - a paraméteres datatype-deklarációhoz hasonlóan - megadhatunk típusparamétereket is, pl.

fun ('a, 'b) f (x, y) = ((x :'a) , (y :'b));
val ('a, 'b) f = fn : 'a * 'b -> 'a * 'b
ami fokozott típusellenőrzést tesz lehetővé. Amíg a következő függvénydefiníció símán lefordul:

fun f (x,ys) = x::ys;
val 'a f = fn : 'a * 'a list -> 'a list
addig ugyanennek 'a-val és 'b-val paraméterezett változatát az mosml hibásnak mondja, mert a programozó típusparaméterekkel kifejezett szándéka és a függvény definíciója között ellenmondást lát:

! Toplevel input:
! fun ('a, 'b) f (x :'a , ys : 'b) = x::ys;
!                                       J
! Type clash: expression of explicit type 'b
! cannot have type
!   'a list
A válaszoló jól tippelt, az mosml értelmező a jegyzet írásakor még másképpen működött.

15.2. Kérdés.
Az egyik SML gyakorlófeladat a List.length újraírása. Ezt nem fogadta el a gyakorlórendszer: val len = foldl (fn (a,b) => b+1) 0.

Ha az a változó típusát leszűkítem, vagy fun alakban írom (fun len xs = foldl (fn (a,b) => b+1) 0), akkor minden OK.

A kérdéseim:

  1. Miért nem működik az eredeti?
  2. Melyek azok a kifejezések, amelyeknél a fun a x = f x alakot nem lehet átírni az val a = f alakba?

15.2. Válasz.
Hallgató: Sikerült rátalálnod a típusos funkcionális nyelvek egyik gyengéjére. A gond az, hogy a len polimorf függvény, ráadásul pont a ki nem írt argumentumának a típusa polimorf. Ezt sajnos a típusrendszer (bizonyos ismert, sok helyen leírt okok miatt) toplevel szinten nem tudja elfogadni. Ha kiírod az argumentumot (akár fun kulcsszóval, akár lambda alakban), akkor feloldod a problémát.

Ha többet szeretnél megtudni az okáról, a neten számos ezzel foglalkozó cikk, leirás található.

Oktató: A jelenség megértéséhez meg kell ismerni az expanzív és a nemexpanzív kifejezés fogalmát, és azt, hogy hogyan értelmezi ezeket az SML nyelv, és hogyan kezelik az egyes SML-értelmezők.

A polimorfizmusról és a kifejezések expanziójáról egy 8+1 oldalas magyar nyelvű összefoglalót felraktam a tárgy honlapjára:

A Moscow ML Owner's Manual ,,Value polymorphism'' c. 12. fejezete ugyanerről angolul ad rövid áttekintést (lásd pl. <http://dp.iit.bme.hu/download.html>, Moscow ML Owner's Manual).

Akit még bővebben érdekel, keressen ,,value polymorphism'' témájú cikkeket a weben.


Deklaratív programozás - FP-GYIK
2005. március 1.