Én úgy gondolkoztam, hogy mivel az x függvény argumentumul kapja y-t, amely szintén függvény, ezért ('a -> 'b) -> 'a lesz az x típusa, eddig a helyes megoldás is ilyen. De ezután ebből egy olyan függvény lesz, amely 'b típust ad eredményül (az y miatt), de az argumentuma egy függvény (x y), és ezért ('b -> 'a ) -> 'b.
Tehát szerintem az egész : (('a -> 'b) -> 'a) -> ('b -> 'a) -> 'b, ami nyilván nem jó, mert begépeltem az ML értelmezőnek is... :(
Persze nyilvánvaló módon nem fogadhatja el az mosml egyiket sem, ui. az (int * int) * int egy olyan pár típusa, amelynek az első tagja maga is egy pár, az int * (int * int) pedig egy olyan pár típusa, amelynek a második tagja maga is egy pár. Ezzel szemben az int * int * int egy hármas típusa.
A kérdező folytatja: Oké, tényleg egyszerű, csak azt honnan lehet tudni, hogy mind az s, mind az r paraméter (argumentum)? r miért nem részlegesen alkalmazható függvény? Ha pl. fun f x y z = y x z, akkor ebben mind az x, mind a z egyszerűen paraméter, és az x nem részlegesen alkalmazható függvény?
Oktató: Onnan tudható, hogy melyik név áll függvényalkalmazási-pozícióban, és melyik nem. A függvényalkalmazás a lehető legerősebben kötő művelet, a kiértékelés (hacsak zárójelek vagy precedenciák nem módosítják) mindig balról jobbra halad. A függvény nevét az argumentumtól egy vagy több szeparátor (formázó karakter vagy kerek nyitó zárójel) választja el. (A vessző, pontosvessző nem szeparátor!)
Nézzük még egyszer a kérdéses függvényt:
Nos, én kidolgoztam egy módszert a típuslevezetésre, de az itt nem működik. Miért nem? Nem tudom. :( Az mosml az alábbi válasszal áll elő:
Ezt kitűnően reprezentálja a zárójeles kifejezés. DE! Hát előtte is van egy a, annak miért nem a megállapított típusát írja ki az mosml??? Az én módszerem ezt adja:
Mivel az SML-ben (a Prologgal ellentétben!) nincs egyesítés, csak behelyettesítés van, a bal oldalon kétszer is előforduló a argumentum valójában két, egymástól független argumentumot jelöl! Nézzünk egy nagyon egyszerű esetet és az mosml válaszát:
Következő példaként nézzük az f két alkalmazását mosml alatt:
A map, típusa ('a -> 'b) -> ('a list -> 'b list), az o bal oldalán van, ezért ('e -> 'g) = ('a -> 'b) -> ('a list -> 'b list), és így e' = ('a -> 'b) és 'g = ('a list -> 'b list).
Az o jobb oldalán a v a van, ezért a típusának 'd -> 'e-nek kell lennie. Az a-ra semmilyen megkötés nincs, jelöljük a típusát 'c-vel. A v típusa tehát: 'c -> ('d -> 'e).
A megfelelő helyre behelyettesítve, amit csak lehet, kapjuk az f típusát:
Oktató: Az xs bevezetése valóban felesleges (nevezhetjük megtévesztésnek is), hiszen
List.find típusa és alkalmazásának eredménye, továbbá SOME és NONE típusa helyesen a következő.
Ebben a feladatban mind y első előfordulása az = jobb oldalán, mind x függvényalkalmazási pozícióban van, az x függvény paramétere y, az y függvény paramétere pedig az x y függvényalkalmazás eredménye.
A típusokról semmi konkrétumot nem tudunk meg, ezért az y típusa a lehető legspecifikusabban így írható fel: 'a -> 'b. Ha ez megvan, már rutinfeladat a levezetés:
Szóljatok, ha valami nem stimmel, vagy nem érthető...
Másik hallgató: Megfogalmazom másképpen, formálisabban, hátha valakinek segítek vele. A 3 <> 4 = false, a típusa bool, ez az ún. egységelem (trükkös). Ebből következően a op <> bool * bool -> bool típusú ebben a feladatban. Tehát a listának, amelyre az x-et alkalmazzuk, bool list-nek kell lennie. Ezért
Ehhez a feladathoz kérek segítséget. A probléma az, hogy ha nem kezelem le az xs = [] esetet, akkor nem enged tovább, ha lekezelem, akkor viszont a visszaadott érték nem megfelelő, hiszen nem tudom visszaadni a listabeli elem típusát. Mi a megoldás?
Gyorsan megírható az a változata, amely az i = 0 és az i > length xs speciális eseteket is automatikusan kezeli, ha a List.nth : 'a list * int -> 'a és a length : 'a list -> int függvényeket alkalmazzuk. List.nth alkalmazásához tudni kell, hogy a lista fejének (bal szélső elemének) 0 az indexe.
A 'a, 'b, 'c stb. tetszőleges típust jelölnek, típusváltozóként foghatók fel, kb. úgy, mint a C++ban a template. A típuslevezetést úgy kapjuk meg, hogy a rendszer felteszi, hogy x-nek 'a típusa van, ekkor viszont a válasz is 'a típusú, hiszen pontosan x-et adja vissza a függvény. A -> jel a leképzés jele, bal oldalán a függvény argumentumának, jobb oldalán a függvény által visszaadott értéknek a típusa latható. Ez a függvény tehát alkalmazható tetszőleges típusú paraméter esetén, és ugyanolyan típusú értéket ad vissza.
A * jel a típuskifejezésben az enneseket jelöli (egyébként a direktszorzat jelét akarja sugallni), és erősebben köt, mint a ->, tehát a kifejezés így értelmezendő:
Itt a list típusoperátor az új: egy adott típus mögé írva az ilyen típusú elemekből képzett listát jelöli. Balra köt, így pl. 'a list list egy 'a típusú elemekből álló listák listáját jelöli.
Vagyis a valami fugggény paraméterként kap egy 'a típusú értéket: ez lesz az x. Visszaad egy függvényt. Ez a visszaadott függvény paraméterként kap egy 'b típusú értéket: méghozzá az y-t. Ennek visszatérési értéke az x érték lesz, amelyről ugye már tudjuk, hogy 'a típusú.
Hogy egy kicsit érthetőbb legyen a dolog, nézzük egy példát valami x y-ra, azaz a valami függvény ,,teljes'' alkalmazására:
A függvény típusa most: real -> real, ugyanis explicite előírtuk, hogy a paramétere real típusú legyen, és mivel a visszatérési értéke megegyezik az átadott paraméter értékével (identitásfüggvényről lévén szó), ezért nyilván az is real típusú.
Másrészt meghatározó a számkonstansok típusa is. Így pl.
A kérdező folytatja: Amire még kíváncsi lennék:
A kérdező folytatja: A kérdésem ugyanaz, mint előbb...
Oktató: Nem lesz meglepő, amit írok: el kell végezni a behelyettesítéseket...