member :: (Eq a) => a -> [a] -> Bool


member el [] = False
member el (x:xs) = (x == el) || (member el xs)


-- Costruiamo i nodi a partire da numeri interi

data Node = Node Int
     deriving Show

instance Eq Node where
   (Node n) == (Node m) = (n == m)

-- Costruiamo un grafo a partire dalla lista delle coppie dei nodi adiacenti.
-- Se N1 ed N2 sono adiacenti supponiamo basti avere (N1,N2) nella lista
-- se c'e' anche (N2,N1) non cambia nulla

data Graph = Graph [(Node,Node)]
       deriving Show

-- Un grafo da usare come test

myGraph = Graph [(Node 1,Node 2),(Node 2,Node 3),(Node 3,Node 4),(Node 1,Node 5),(Node 5, Node 2),(Node 1,Node 6),(Node 6, Node 7)]


-- Costruiamo un cammino a partire dalla lista dei nodi che lo definiscono

data Path = Path [Node]
      deriving Show


data Set a = Set [a]
      deriving Show

-- predicato su insiemi

isEmpty :: (Set a) -> Bool

isEmpty (Set []) = True
isEmpty s = False


-- funzione che restituisce la lista a partire dalla quale e' stato
-- costruito un insieme

makelist :: (Set a) -> [a]

makelist (Set l) = l


-- unione di insiemi

union :: (Set a) -> (Set a) -> (Set a)

union (Set l1) (Set l2) = Set (l1++l2) 


-- unione generalizzata (su lista di insiemi)

unionGen :: [(Set a)] -> (Set a)

unionGen [] = Set []
unionGen (st:sts) = union st (unionGen sts)


-- funzione che prende un nodo N, un path N1,N2,...Nm e restituisce il
-- path N,N1,N2,...Nm
-- Se il path e' vuoto allora restituisce il path vuoto (non N)

putOnHeadPath :: Node -> Path -> Path

putOnHeadPath el (Path []) = Path []
putOnHeadPath el (Path ns) = Path (el:ns)


-- funzione che restituisce, dato un grafo ed un nodo, l'insieme
-- dei nodi adiacenti al nodo in input

adiacentSet :: Graph -> Node -> (Set Node)

adiacentSet (Graph []) n = Set []
adiacentSet (Graph ((n1,n2):l)) n  | (n == n1)    =  (union (Set [n2]) (adiacentSet (Graph l) n) )
                                   | (n == n2)    =  (union (Set [n1]) (adiacentSet (Graph l) n) )
                                   | otherwise    =  (adiacentSet (Graph l) n)


-- funzione (a cui in realta' andrebbe dato un nome piu' significativo)
-- che restituisce un grafo simile a quello di input, ma in cui non e'
-- presente il nodo dato come secondo input

remove :: Graph -> Node -> Graph

remove (Graph l) n = Graph [ (n1,n2) | (n1,n2) <- l,  (n /= n1),  (n /= n2) ]


-- funzione che restituisce l'insieme dei cammini

findPaths :: Graph -> Node -> Node -> (Set Path)


findPaths g n m  |  (n == m)          = Set [Path [n]]
                 |  (isEmpty (adiacentSet g n)) = Set []
                 |  otherwise          = Set (map (putOnHeadPath n)
                                                  (makelist (unionGen [(findPaths (remove g n) nd m) | nd <- (makelist (adiacentSet g n)) ] ) )
                                             )
               

