-module(subtype). -export([newCheck/4, parametricSubtyping/1, loopmanager/2]). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %ESEMPI: %Funzione che restituisce una funzione per il controllo dei sottotipi, la cui lista di relazioni di tipi base èomposta dalla sola relazione Int <: Real : %R=subtype:parametricSubtyping([{int, real}]). %Richiesta per controllare se èossibile la sostituzione di ?Int <: ?Real %R({in, int}, {in, real}). %%Funzione che restituisce una funzione per il controllo dei sottotipi, la cui lista di relazioni di tipi base èomposta dalle relazioni t1b <: t1a e t2a <: t2b : %Q=subtype:parametricSubtyping([{t1b, t1a}, {t2a, t2b}]). %Richiesta per controllare se èossibile la sostituzione di ![t1a, ![t2a]] <: ![t1b, ![t2b]] : %Q({out, [t1a, {out, [t2a]}]}, {out, [t1b, {out, [t2b]}]}). %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% %Sfruttando la currificazione, creo una funzione che accetta le richieste per verificare se due tipi sono sottotipi %(Richiede di impostare la lista di sottotipi). parametricSubtyping(ListSubtype) -> fun(Type1, Type2) -> PIDmanager=spawn(subtype, loopmanager, [0, self()]), spawn(subtype, newCheck, [Type1, Type2, ListSubtype, PIDmanager]), receive Y -> Y end end. %NewCheck si occupa di avvertire il loopmanager della presenza di un nuovo processo e di eseguire il check newCheck(Type1, Type2, ListSubtype, PIDmanager) -> %Segnalo al loopmanager che c'èn nuovo processo PIDmanager!newCheck, %Avvio il check check(Type1, Type2, ListSubtype, PIDmanager). %Check verifica che due tipi tipi siano sottotipi %Caso 1: I due tipi sono entrambi tipi di canali check({_, []}, {_, []}, _, PIDmanager) -> PIDmanager!true; check({IoTChannel1, Type1}, {IoTChannel2, Type2}, ListSubtype, PIDmanager) -> %Se i tipi di canali sono entrambi sia di input che output if ((IoTChannel1==in_out)and(IoTChannel2==in_out)) -> %Accetta solo se i due tipi T sono uguali: ^T <: ^T if(Type1==Type2) -> PIDmanager!true; true -> PIDmanager!false end; %Se ^T <: ?S oppure ^T <: !S : si noti che ^T <: ?T e che ^T <: !T ((IoTChannel1==in_out)and( (IoTChannel2==in) or (IoTChannel2==out))) -> check({IoTChannel2, Type1}, {IoTChannel2, Type2}, ListSubtype, PIDmanager); %Se ?T <: ?S ((IoTChannel1==in)and(IoTChannel2==in)) -> check(Type1, Type2, ListSubtype, PIDmanager); %Se !T <: !S ((IoTChannel1==out)and(IoTChannel2==out)) -> check(Type2, Type1, ListSubtype, PIDmanager); %In tutti gli altri casi: non èalido true -> PIDmanager!false end; %Caso 2: Entrambi i tipi sono liste di tipi check([], [], _, PIDmanager) -> PIDmanager!true; check([Type1|ListType1], [Type2|ListType2], ListSubtype, PIDmanager) -> %Devo creare un secondo processo che si occupa di controllare i due Type spawn(subtype, newCheck, [Type1, Type2, ListSubtype, PIDmanager]), %Eseguo la check sulle restanti parti delle due liste check(ListType1, ListType2, ListSubtype, PIDmanager); %Caso 3: ho due tipi base check(Type1, Type2, ListSubtype, PIDmanager) -> %O esiste la relazione di sottotipi presente nella lista di sottotipi base IsInSubtype=lists:member({Type1, Type2}, ListSubtype), IsValidType1=validateType(Type1, ListSubtype), IsValidType2=validateType(Type2, ListSubtype), if(IsInSubtype==true) -> PIDmanager!true; %O i due tipi sono uguali e validi (IsValidType1 and IsValidType2 and (Type1==Type2)) -> PIDmanager!true; %Oppure non sono sottotipi true -> PIDmanager!false end. %Verifica che il tipo sia valido validateType(Type, ListSubtype) -> %O il tipo èresente all'interno della lista dei sottotipi(puòovarsi come primo o secondo %elemento della tupla) IsInSubtype1=(lists:keysearch(Type, 1, ListSubtype)/=false), IsInSubtype2=(lists:keysearch(Type, 2, ListSubtype)/=false), if(IsInSubtype1 or IsInSubtype2) -> true; %Oppure non èn tipo valido true -> false end. %Loop che riceve da tutti i processi check se i sottotipi sono corretti. %Prende come argomento il numero di processi check attualmente in esecuzione e il processo che lo ha chiamato. %A fine esecuzione, invia al processo chiamante "true" se i due elementi sono sottotipi, altrimenti "false" loopmanager(Nchecks, PID) -> receive %Se ho ricevuto un true, significa che c'èn processo in meno che controlla i sottotipi true -> N=Nchecks-1, if %Se era l'ultimo, invio true (N == 0) -> PID!true; %Altrimenti, continua il ciclo true -> loopmanager(N, PID) end; %Se ho ricevuto false, allora i due tipi non sono sottotipi false -> PID!false; %Se ho ricevuto NewCheck, c'èn nuovo processo e quindi aggiorno il contatore dei processi newCheck -> loopmanager(Nchecks+1, PID) end.