A SICStus Prolog minden eljárást valamilyen modulban helyez el. Amig nem intézkedünk másképp, az eljárások alaphelyzetben a user modulba kerülnek. Ha Prolog programunkat strukturálni kívánjuk, akkor ún. modul-állományokat kell létrehoznunk. Egy állományban egy modult tudunk elhelyezni, az állomány első programeleme egy modul-parancs kell legyen:
Itt Funktor1, ... a modulból exportálni kivánt eljárások funktorai (azaz Név/Aritás alakú kifejezések, ahol Név egy atom, Aritás egy egész). Például, ha egy korábban definiált fennsik/3 eljárást egy modulba kivánjuk foglalni, akkor a szükséges eljárásokat be kell írnunk egy állományba, mondjuk plato.pl -be, és ennek az állománynak az elejére el kell helyeznünk a következő parancsot:
Ha ezután be akarjuk tölteni ezt a modult, akkor a SICStus rendszer promptjánál ki kell adnunk egy use_module parancsot, argumentumában az állománynévvel:
Ez a parancs az adott állományban levő modult betölti, és az általa exportált összes eljárást importálja a kurrens modulba (példánkban a user modulba). Ezáltal az importált eljárások ebből a modulból hivhatókká válnak. Ugyanezt a beépitett eljárást használhatjuk a SICStus könyvtárak betöltésére is, pl. a lists könyvtárat a következőképpen tölthetjük be:
A use_module beépitett eljárásnak van egy kétargumentumú változata, ez betölti a modult, de csak azokat az eljárásokat importálja, amelyek funktorai szerepelnek a második argumentumbeli import-listában. Pl:
csak a last/2 eljárást fogja láthatóvá tenni, a többi könyvtári eljárást nem. Ekkor például lehet egy saját append eljárásunk, anélkül, hogy ez a könyvtári példánnyal összeütközésbe kerülne. A use_module parancs szerepelhet egy állományban, akár egy modul-állományban is. Ez utóbbi esetben csak ebbe a modulba fogja importálni a betöltött eljárásokat. Ugyanazt a modul-állományt több modulba is betölthetjük, ez nem jár felesleges memóriafoglalással, mivel a SICStus Prolog rendszer az eljárásokat csak egy példányban tárolja.
A SICStus Prolog rendszer modulfogalma nem szigorú. Bármely betöltött eljárás meghívható, ha az ún. modul-kvalifikált hívási formát használjuk, azaz az eljáráshívás elé írjuk a modulnevet, attól a kettőspont operátorral elválasztva. Ha például a fennsík kereső programot a fent példaként idézett módon foglaltuk modulba, és azt betöltjük, akkor a fennsik/3 eljárást modul kvalifikálás nélkül tudjuk hívni, de a többi eljárást is meghívhatjuk, például:
A SICStus rendszernek ez a tulajdonsága különösen hasznos modularizált programok nyomkövetésénél.
Végezetül következzék néhány, a magasabbrendű eljárások használata során felmerülő, a modularitással kapcsolatos fontos tudnivaló. A magasabbrendű (meta-) eljárás egy olyan eljárás, amelynek egy másik eljárás az argumentuma. Világos, hogy ha modulközi meta-eljárásokat írunk, azaz a meta-eljárás által meghívandó eljárás más modulban van, akkor szükség van arra, hogy az eljárás meta-argumentumát modul-kvalifikált módon adjuk át. Ezért a meta-eljárásokra egy meta_predicate deklarációt kell megadnunk, amelyben jelezzük, hogy melyek az eljárás-argumentumok. A meta-deklaráció formája:
Itt az argleiró lehet a : jel, annak jelzésére, hogy az adott argumentum egy eljárás, vagy bármilyen más atom a többi argumentum jelzésére. Ez utóbbi helyeken szokás a be- ill. kimenő jellegre utaló jeleket elhelyezni (+,-,?).
Alapvetően kétféle modulfogalom lehetséges:
Egy név minden előfordulása (eljárás, konstans, struktúra) vagy látható (visible) vagy lokális (local) az adott modulban. A lokális nevek csak az adott modulban láthatók, azaz más modulban nem nevezhetők meg. Ez legegyszerűbben úgy képzelhető el, hogy egy r lokális névnek egy m modulban való minden előfordulása átneveződik pl. az 'm:r' névvé.
Előnyök:
Hátrányok:
A kívülről való láthatóságot eljárásokhoz és nem nevekhez kötjük. Az adatnevek általában mindig láthatóak.
Előnyök:
Hátrányok:
Futás közben a rendszer állandóan nyilvántartja, mely modulban vagyunk. Ez közönséges eljárások esetén az eljárás definícióját tartalmazó modul. A meta-eljárásokat (pl. p/1 alább) azonban átlátszóaknak kell deklarálni.
Az ilyen eljárások esetén a modul-környezet a hívótól öröklődik. A modul-környezetet használjuk annak megállapitására, hogy egy meta-hívást mely modulban értelmezzünk. Például:
A p eljárás meghívásakor m2 marad a modul-környezet, mert p/1 átlátszó, így X hívásakor az X=r eljárást m2-ben keressük.
A meta-eljárásoknál meg kell nevezni a meta-argumentumpoziciókat, pl. egy olyan p/3 esetén, melynek a 3. argumentuma eljárás:
A meta_predicate deklarációt minden olyan modulban szerepeltetni kell, ahol az adott eljárást meghívjuk! A fordítóprogram az adott argumentumpoziciót minden hívásban kiegészíti, pl: