Minta, mintaillesztés

10.1. Kérdés.
Az alábbi szomszed1 (c,d) függvényt az mosml a következő figyelmeztetéssel fordítja le: Some cases are unused in this match.

A függvény feladata az, hogy egy listába gyűjtse azokat a mátrixelemeket, amelyekre egy adott (a,b) koordinátájú mátrixelemről ráléphetek (a a sor-, b az oszlopindex). A kódot az órán bemutatott joszam10 (a,b) függvényhez hasonlóan próbáltam megírni.

Vázlatosan (a kipontozott helyeken a megértéshez nem szükséges értékdeklarációk és feltételvizsgálatok vannak):

fun szomszed (a, b) =
      let val alsosor = a+1
          val szelsosor = b+1
          val szsorutan = b+2
          val kozepa = a
          val kozepb = b
          fun szomszed1 (alsosor, szsorutan) = []
            | szomszed1 (c, szsorutan) =
                                  szomszed1(c+1, szelsosor-2)
            | szomszed1 (kozepa, kozepb) =
                                 szomszed1(kozepa, szelsosor)
            | szomszed1 (c, d) =
                 .................
                 ..................
                if ........ then  ujelem :: szomszed1(c, d+1)
                            else  szomszed1(c, d+1)
    in
       szomszed1 (a-1,b-1)
    end

10.1. Válasz.
Oktató: A függvénydefinícióban formális paraméterként használt kifejezések olyan kifejezésminták, röviden minták, amelyekre az mosml majd megpróbálja illeszteni a függvény alkalmazásakor használt aktuális paramétereket (argumentumokat); ezt nevezzük mintaillesztésnek. Az SML-kifejezéseknek csak egy részhalmaza használható mintaként. További részletek az SML-jegyzet Az SML alapnyelv szintaxisa c. függelékében, valamint a Moscow ML Language Overview-ban találhatók. Összefoglalva:


Minta Magyarázat
Mindenesjel (_) Mindenre illeszkedik; a definíció jobb oldalán nem használható
Állandó Csak a meghatározott értékre illeszkedik
Név (azoosító) Mindenre illeszkedik
Adatkonstruktor Csak meghatározott szerkezetű, ill. tartalmú értékre illeszkedik
Rekord Csak adott szerkezetű rekordra illeszkedik
Ennes (nullas is) Csak adott szerkezetű ennesre illeszkedik
Lista Csak adott szerkezetű listára illeszkedik


A konkrét kérdésre válaszolva: a szomszed1 függvénynek már az első klózában olyan minta van, amely az összes lehetséges esetet lefedi, ezért a többi klóz kiválaszására soha nem kerül sor. (Egyébként a val alsosor = a+1 értékdeklarációnak nincs semmi hatása a mintára.)

A kérdező folytatja: Akkor hogyan lehet ezt a problémát megoldani?

Oktató: Mint láttuk, csak bizonyos kifejezések lehetnek minták az SML-ben, aritmetikai kifejezések és szinonimák nem. Ezért a szomszed1 függvényben - úgy, ahogyan a programrészletből vélhetően használni szeretné - sem alsosor, sem kozepa nem lehet minta, de nem lehet minta a fentiek szerint a+1 sem.

Egy aritmetikai kifejezés értéke csak a függvény törzsébe beírt kóddal vizsgálható meg, pl. az adott esetben az x aktualis értéke a szomszed1 függvény törzsében így: if x = alsosor then ...

A mintaillesztésnek erős korlátai vannak az SML-ben. Más funkcionális nyelvekben (pl. gofer, clean, haskell, Alice) a mintaillesztés sokkal rugalmasabb.

10.2. Kérdés.
Meg tudná mondani valaki, hogy a következő függvényre miért kapom a Pattern matching is not exhaustive hibaüzenetet?

fun uj_satrak ((fx,fy), ujak, iranyeg, [],[]) =
                                             (ujak, iranyeg)
  | uj_satrak ((fx,fy), ujak, iranyeg,
                       (ix,iy)::iranyok, egt::egtajak) = ...

10.2. Válasz.
Oktató: Azért, mert a függvény azokra az esetekre nem illeszkedik (nincs rájuk minta), amikor az iranyok és az egtajak listák közül az egyik üres, a másik meg nem.

Amúgy ez nem hibaüzenet (error message), csak figyelmeztetés (warning), de erősen ajánljuk, hogy a figyelmeztetések okát is szüntesse meg a programjaiban, mert eltakarhatják az igazi hibákat.

Talán arra gondolt, hogy nem fordulhat elő olyan eset, amikor az iranyok és az egtajak közül az egyik üres, a másik meg nem. Ha ebben 100%-ig biztos, akkor a két sor megfordításával és apró módosításával ([] helyett a _ minta használatával mindkét esetben) a figyelmeztetés oka megszüntethető:

fun uj_satrak( (fx,fy), ujak, iranyeg,
                       (ix,iy)::iranyok, egt::egtajak) = ...
  | uj_satrak( (fx,fy), ujak, iranyeg, _, _) =
                                            (ujak, iranyeg);
De biztonságosabb, ha minden esetet külön kezel, és kivételt jelez hiba esetén. A kivétel jelzését főleg a program élesztése közben tanácsoljuk, később kiszedhető a programból.

10.3. Kérdés.
Meg tudja mondani valaki, hogy miért kapok Pattern matching is not exhaustive warning-ot:

fun megfelel (Ss, Os, Fasor, MX, MY,
              (hanyadik, (sx, sy)::satrakK, _, AS,AO)) =
      if sx >= 1 andalso sx <= MX andalso
           sy >= 1 andalso sy <= MY andalso
           nemszomszed((sx,sy),satrakK) andalso
           mennyiseg_ok(AS,Ss, hanyadik) andalso
           mennyiseg_ok(AO, Os, hanyadik) andalso
           not(Tage((sx,sy),Fasor))
      then true
      else false
  | megfelel (Ss, Os, Fasor, MX, MY, (0,[],_,AS,AO )) =
                                                      false
  | megfelel ([], _, _, _, _, _) = false
  | megfelel (_, [], _, _, _, _) = false
  | megfelel (_, _, [], _, _, _) = false;

10.3. Válasz.
Oktató: Mivel a kódrészlet nem teljes, csak tippelni tudok. Valószínűleg arra figyelmeztet, hogy nincs lefedve a következő eset: az Ss, Os és Fasor listák egyike sem üres, miközben az első klózban (sx, sy)::satrakK mintával jelölt lista mégiscsak üres. Egyébként már több ilyen kérdésre válaszoltunk, érdemes azokat is elolvasnia.

Néhány további tanács a programrészlethez:

10.4. Kérdés.
Amikor betöltöm a nagyházimat az mosml-be, a következő üzenetet kapom:

! ....kitoltes(array,y,x,maxy,maxx,SOL,OOL,RefPL,1) =
!     if array<>[] then       
!     if x<maxx andalso y<=maxy then
!         kitoltes(check1(addelement(array,y,1),
!                         ..........
!         kitoltes(check0(addelement(array,y,0),
                          ..........
!      else [addelement(array,y,0)]
!      else [].
! Warning: pattern matching is not exhaustive
A program utána fut, tehát nem hiba, hanem ,,csak'' figyelmeztetés. Az a baj, hogy valszeg emiatt a hiba miatt bugos a nagyházim, és nem tudom, hogy mit jelent ez az üzenet. Tulajdonképpen elég lenne azt tudnom, hogy mikor ad ilyen figyelmeztetést az mosml, mert abból már ki tudom találni, hogy mi a hiba.

10.4. Válasz.
Oktató: Ezt már több előadáson elmondtam, több dián le van írva, de röviden megismétlem.

Egy függvényben a paraméter(ek) összes lehetséges értékkombinaciójára kell egy-egy klózt írni, különben a Match (lefedetlen esetek) figyelmeztetést írja ki az értelmező. Csak figyelmeztetés, mert előfordulhat, hogy az adott környezetben az adott kombináció sohasem fordulhat elő, de biztosabb ilyenkor is az összes lehetséges esetre klózt írni.

Gondolja át, hogy milyen eset(ek)et nem fedett le, és legalább valami értelmes hibaüzenetet írjon ki az eddig lefedetlen esetekben, amelyből következtethet a hiba okára. Ha jobb ötlete nincs, írjon egy minden esetet lefedő klózt (... _ = ...), és írja ki a képernyőre az adatok szignifikáns részét. Ez persze csak otthon, teszteles közben segíthet. Ha kell, bővítse a tesztesetek körét.


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