Pages: [1]   Go Down
Print
Author Topic: Subtype in Erlang  (Read 783 times)
0 Members e 1 Utente non registrato stanno visualizzando questa discussione.
rondey
Matricola
*
Offline Offline

Posts: 74


« on: 10-05-2016, 15:02:04 »

Code:
-module(subtype).
-export([check/4, manager/4, loopmanager/3, read/0]).

%Channel1={in, type}

%Channel2={{out, [type1, Channel]}}

%Subtype={typeName1, typeName2}

%ListSubtype=[{typeName1, typeName2}, {typeName3, typeName4}]

%ESEMPI:
%subtype:manager({in, int}, {in, real}, [{int, real}], self()).  ---> true
%subtype:manager({out, [t1a, {out, [t2a]}]}, {out, [t1b, {out, [t2b]}]}, [{t1b, t1a}, {t2a, t2b}], self()).

loopCheckSubType(_, _, []) -> false;
loopCheckSubType(TypeName1, TypeName2, [{Tn1, Tn2}|ListSubtype]) ->
    if ((TypeName1==Tn1) and (TypeName2==Tn2)) -> true;
        (TypeName1==TypeName2)                 -> true;
        true                                   -> loopCheckSubType(TypeName1, TypeName2, ListSubtype)
    end.

check({_, []}, {_, []}, _, PIDmanager) -> PIDmanager!true;
check({IoChannel1, TypeName1}, {IoChannel2, TypeName2}, ListSubtype, PIDmanager) ->
    if  ((IoChannel1==in_out)and(IoChannel2==in_out)) ->
                                if(TypeName1==TypeName2) -> PIDmanager!true;
                                    true  -> PIDmanager!false
                                end;
        (((IoChannel1==in_out)and( (IoChannel2==in) or (IoChannel2==out)))and(TypeName1==TypeName2)) -> PIDmanager!true;
        ((IoChannel1==in)and(IoChannel2==in)) ->
                                check(TypeName1, TypeName2, ListSubtype, PIDmanager);
        ((IoChannel1==out)and(IoChannel2==out)) ->
                                check(TypeName2, TypeName1, ListSubtype, PIDmanager);                       
        true -> PIDmanager!false
       
end;
check([], [], _, PIDmanager) -> PIDmanager!true;
check([TypeName1|ListType1], [TypeName2|ListType2], ListSubtype, PIDmanager) ->
        spawn(subtype, check, [TypeName1, TypeName2, ListSubtype, PIDmanager]),
        PIDmanager!newCheck,
        check(ListType1, ListType2, ListSubtype, PIDmanager);
%Caso in cui i due TypeName non sono liste
check(TypeName1, TypeName2, ListSubtype, PIDmanager) ->
                                                        Bool=loopCheckSubType(TypeName1, TypeName2, ListSubtype),
                                                        PIDmanager!Bool.

loopmanager(Nchecks, ListChannel, PIDfather) ->
           
         
         receive

              true          ->    N=Nchecks-1,
                                          if
                                             (N == 0)  -> PIDfather ! {accepted, ListChannel}, true;
                                              true           -> loopmanager(N, ListChannel, PIDfather)
                                          end;
              false  ->  PIDfather ! {rejected, ListChannel};

              newCheck  ->  N=Nchecks+1, loopmanager(N, ListChannel, PIDfather)
          end.


manager(Channel1, Channel2, ListSubtype, PIDfather) ->
               Loop=spawn(subtype, loopmanager, [1, {Channel1, Channel2}, PIDfather]),
               spawn(subtype, check, [Channel1, Channel2, ListSubtype, Loop]).

read() -> receive Y -> Y end.

Logged
Franco Barbanera
Moderator
Forumista Eroico
*****
Offline Offline

Posts: 2.622



WWW
« Reply #1 on: 11-05-2016, 10:05:12 »

E un minimo di commento al codice!?!?!

FB
Logged
Franco Barbanera
Moderator
Forumista Eroico
*****
Offline Offline

Posts: 2.622



WWW
« Reply #2 on: 11-05-2016, 10:09:16 »

Ci deve essere comunque una funzione di DUE argomenti (due tipi) che restituisca vero o falso!

FB
Logged
Franco Barbanera
Moderator
Forumista Eroico
*****
Offline Offline

Posts: 2.622



WWW
« Reply #3 on: 11-05-2016, 10:11:53 »


%subtype:manager({out, [t1a, {out, [t2a]}]}, {out, [t1b, {out, [t2b]}]}, [{t1b, t1a}, {t2a, t2b}], self()).

Quali sarebbero i due tipi che si utilizzano in questo esempio?

FB
Logged
rondey
Matricola
*
Offline Offline

Posts: 74


« Reply #4 on: 12-05-2016, 15:10:50 »

Aggiornato con l'inserimento di commenti, qualche aggiustamento e uso della currificazione:
Code:
-module(subtype).
-export([check/4, parametricSubtyping/1, loopmanager/2]).


%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%ESEMPI:
%Funzione che restituisce una funzione per il controllo dei sottotipi, la cui lista di relazioni di tipi base è composta dalla sola relazione Int <: Real :
%R=subtype:parametricSubtyping([{int, real}]).

%Richiesta per controllare se è possibile 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 è composta dalle relazioni t1b <: t1a  e  t2a <: t2b :
%Q=subtype:parametricSubtyping([{t1b, t1a}, {t2a, t2b}]).

%Richiesta per controllare se è possibile 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(TChannel1, TChannel2) ->
                                            spawn(subtype, check, [TChannel1, TChannel2, ListSubtype, self()]),
                                            loopmanager(1, {TChannel1, TChannel2})
                                     end.
      
%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 è valido
        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, check, [Type1, Type2, ListSubtype, PIDmanager]),
        %Segnalo al loopmanager che c'è un nuovo processo
        PIDmanager!newCheck,
        %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 i due tipi sono uguali
                                                if(Type1==Type2) -> PIDmanager!true;
                                                %Oppure verifico l'esistenza di una relazione di sottotipi dalla lista di sottotipi base
                                                    true         -> Bool=lists:member({Type1, Type2}, ListSubtype),
                                                                    PIDmanager!Bool
                                                end.

%Loop che riceve da tutti i processi check se i sottotipi sono corretti.
loopmanager(Nchecks, ListType) ->
          
        
         receive
              %Se ho ricevuto un true, significa che c'è un processo in meno che controlla i sottotipi
              true          ->    N=Nchecks-1,
                                          if
                                              %Se era l'ultimo, invio true
                                             (N == 0)  -> true;
                                              %Altrimenti, continua il ciclo
                                              true           -> loopmanager(N, ListType)
                                          end;
              %Se ho ricevuto false, allora i due tipi non sono sottotipi
              false  ->  false;
                
              %Se ho ricevuto NewCheck, c'è un nuovo processo e quindi aggiorno il contatore dei processi
              newCheck  ->  loopmanager(Nchecks+1, ListType)
          end.
« Last Edit: 19-05-2016, 13:29:14 by rondey » Logged
rondey
Matricola
*
Offline Offline

Posts: 74


« Reply #5 on: 16-05-2016, 16:50:47 »

Ho modificato il contenuto del precedente post con la nuova versione del programma.
Logged
Ocelot92
Apprendista Forumista
**
Offline Offline

Posts: 301



« Reply #6 on: 17-05-2016, 09:12:09 »

Ecco la mia versione:
Code:
-module(subtype).
-export ([checkPair/4, requestHandler/4, read/0, createSystem/1]).

% This program emulates the Pict's checking type system. You can define your own
% type system by using Erlang's atoms and you can define the subtype relation be
% tween them.
% The function "createSystem" takes a list of lists which represents the type sy
% stem. It's formatted as follow:
%
% SubtypeSystem = [ [TypeA, SubTypeA1, SubTypeA2], [TypeB, SubTypeB1]... ]
% Note: SubTypeA2 is not subtype of SubTypeA1. They are both subtype of TypeA.
%
% Then createSystem returns a function which takes two expressions which represe
% nts a type/channel and returns true or false if the type represented by the fi
% rst input is subtype of the second one (according to the Subtype System define
% d before.
% You can format an input as follow:
%
% Type1 = {IoType, Type}
% Where:
% IoType assumes values:
%   none - Is not a channel.
%   in - Input channel. Pict: !
%   out - Output channel. Pict: ?
%   in_out - Input/Output channel. Pict: ^
% Type can be a type specified in the SubtypeSystem or a list (Pict's tuple).
% Example:
% ![T1 ![T2]] =  {out, [ {none,t1}, {out, [ {none,t2} ] } ] }
%
% Note: The process of checking the subtype relation is parallalized if tuples a
% re given as input.

% Example:  ![TA ![TB]]  is subtype of  ![T1 ![T2]]? With t1 <: ta, tb <: t2
% IsSubtype = subtype:createSystem([[ta,t1], [t2,tb]])
%
% IsSubtype({out, [{none,ta}, {out, [{none,tb}]}]},   {out, [{none,t1}, {out, [{none,t2}] }]})


% It takes the SubtypeSystem and returns a function which takes two types and pa
% ss them to a requestHandler. Then wait for the result by calling read().
createSystem(SubtypeSystem) -> fun( {IOtype1,Expr1}, {IOtype2,Expr2}) ->
requestHandler({IOtype1,Expr1}, {IOtype2, Expr2}, self(), SubtypeSystem),
read()
end.

% When tuples are passed to the handler it first checks if the lists are equals
% and the IOtype is in_out or none. In this trivial case it sends handlerOK to t
% he process which committed the request. Otherwise it "explodes" the request by
% creating n request handlers, where n is the size of the tuples, one for each p
% air. After that it waits for the results by calling the requestHandlerLoop and
% passing to it the number of subprocesses created.
% If there's no match in the IOtypes it sends handlerKO to the process who commi
% tted the request.
requestHandler({IOtype1,[H1|T1]}, {IOtype2, [H2|T2]}, ClientPID, SubtypeSystem) ->
if
((((IOtype1 == in_out) and (IOtype2 == in_out)) or
((IOtype1 == none) and (IOtype2 == none)))
and ([H1|T1]==[H2|T2])) ->
  ClientPID ! handlerOK;
true ->
if
(((IOtype1 == none) and (IOtype2 == none)) or
((IOtype1 == in) and (IOtype2 == in)) or
((IOtype1 == in_out) and ((IOtype2 == in) or (IOtype2 == out)))) ->
explodeRequest([H1|T1],[H2|T2], self(), SubtypeSystem),
requestHandlerLoop(ClientPID, listSize([H1|T1]), {IOtype1,[H1|T1]}, {IOtype2,[H2|T2]});
((IOtype1 == out) and (IOtype2 == out)) ->
explodeRequest([H2|T2], [H1|T1], self(), SubtypeSystem),
requestHandlerLoop(ClientPID, listSize([H1|T1]), {IOtype1,[H1|T1]}, {IOtype2,[H2|T2]});
true ->
ClientPID ! handlerKO
end
end;

% When the requestHandler gets a not-tuple value as Type (by exploding the reque
% st or because of user's input) it calls the checkPair and waits for the result
% in the requestHandlerLoop. Note that this time the results are not given by an
% other requestHandler but by a checkPair function.
requestHandler({IOtype1,T1}, {IOtype2, T2}, ClientPID, SubtypeSystem) ->
checkPair( {IOtype1,T1}, {IOtype2, T2}, self(), SubtypeSystem),
requestHandlerLoop(ClientPID, 1, {IOtype1,T1}, {IOtype2, T2} ).

% Creates n requestHandler processes, where n is the size of the tuples, and it
% passes to them a pair T1 and T2 where T1 is the i-th element of the first list
% and T2 is T1's peer element in the second list.
explodeRequest([], [], ClientPID, SubtypeSystem) -> doNothing;
explodeRequest([H1|T1], [H2|T2], ClientPID, SubtypeSystem) ->
spawn(subtype, requestHandler, [H1, H2, self(), SubtypeSystem]),
explodeRequest(T1, T2, self(), SubtypeSystem).

% It waits for responses from the subprocesses created earlier. When it receive
% an handlerOK/checkerOK it call itself and decrease the number of subprocesses.
% When he gets a handlerKO or checkerKO it sends to the process who committed th
% e request handlerKO.
requestHandlerLoop(ClientPID, NumSubProcesses, Expr1, Expr2) ->
if
(NumSubProcesses == 0) ->
ClientPID ! handlerOK;
true ->
receive
handlerOK ->
requestHandlerLoop(ClientPID, NumSubProcesses -1, Expr1, Expr2);
handlerKO ->
ClientPID ! handlerKO;
checkerOK ->
requestHandlerLoop(ClientPID, NumSubProcesses -1, Expr1, Expr2);
checkerKO ->
ClientPID ! handlerKO
end
end.

% Checks if T1 is subtype of T2 (similarly to requestHandler). If there's a matc
% h with the IOtypes it calls the queueSubtypesystem by passing to it the two ty
% pes. If queueSubtypesystems returns true it sends checkerOK to the handler, ot
% herwise it sends checkerKO.
checkPair({IOtype1,T1}, {IOtype2,T2}, HandlerPID, SubtypeSystem) ->
if
((((IOtype1 == in_out) and (IOtype2 == in_out)) or
((IOtype1 == none) and (IOtype2 == none)))
and (T1==T2)) ->
HandlerPID ! ok;
true ->
if
(((IOtype1 == none) and (IOtype2 == none)) or
((IOtype1 == in) and (IOtype2 == in)) or
((IOtype1 == in_out) and ((IOtype2 == in) or (IOtype2 == out)))) ->
Ris = queueSubtypeSystem(T1, T2, SubtypeSystem);
((IOtype1 == out) and (IOtype2 == out)) ->
Ris = queueSubtypeSystem(T2, T1, SubtypeSystem);
true ->
Ris = false
end,
if
Ris == true ->
HandlerPID ! checkerOK;
true ->
HandlerPID ! checkerKO
end
end.

% Checks if T1 is subtype of T2 iterating through the list SubtypeSystem.
queueSubtypeSystem(T1,T2,[]) -> false;
queueSubtypeSystem(T1,T2, [H|T]) ->
SuperType = lists:nth(1,H),
if
(T2 == SuperType) ->
lists:member(T1,H);
true ->
queueSubtypeSystem(T1,T2,T)
end.

% Utility function.
read() ->
receive
handlerOK -> true;
handlerKO -> false
end.

% Utility. Returns the siT2|Rest2ze of the given list.
listSize([])-> 0;
listSize([H|T]) ->
1 + listSize(T).

Logged

I'm happy to tell you all that...
((λf.λx.f(f(x))) (λy.y^2)) (5)  = 5^4

"Si ma dillo che bisogna cliccare APPLY per crearle le partizioni…" - cit. Utente dopo aver seguito un How-To... .-.
Franco Barbanera
Moderator
Forumista Eroico
*****
Offline Offline

Posts: 2.622



WWW
« Reply #7 on: 17-05-2016, 15:58:13 »

Quote
Entrambi i due tipi

Hanno cambiato la grammatica della lingua italiana senza avvertirmi?

Logged
Franco Barbanera
Moderator
Forumista Eroico
*****
Offline Offline

Posts: 2.622



WWW
« Reply #8 on: 17-05-2016, 16:02:27 »

Quote
newCheck  ->  N=Nchecks+1, loopmanager(N, ListType)

meglio fare

newCheck  ->  loopmanager(Nchecks+1, ListType)
Logged
rondey
Matricola
*
Offline Offline

Posts: 74


« Reply #9 on: 20-05-2016, 14:50:37 »

Pubblico un nuovo aggiornamento del programma. Le principali modifiche sono la validazione del tipo e che ogni nuovo processo inizia con la funzione NewCheck. Con questa funzione sono i figli stessi che avvertono il loopmanager della presenza di un nuovo processo(in questo modo viene assicurato che il loopmanager riceva nel corretto ordine il messaggio di avvenuta creazione del nuovo processo e la fine del processo stesso)
Code:
-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 è composta dalla sola relazione Int <: Real :
%R=subtype:parametricSubtyping([{int, real}]).

%Richiesta per controllare se è possibile 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 è composta dalle relazioni t1b <: t1a  e  t2a <: t2b :
%Q=subtype:parametricSubtyping([{t1b, t1a}, {t2a, t2b}]).

%Richiesta per controllare se è possibile 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'è un 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 è valido
        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 è presente all'interno della lista dei sottotipi(può trovarsi 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 è un 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'è un 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'è un nuovo processo e quindi aggiorno il contatore dei processi
              newCheck  ->    loopmanager(Nchecks+1, PID)
                           
          end.
« Last Edit: 21-05-2016, 10:50:16 by rondey » Logged
Pages: [1]   Go Up
Print
Jump to: