I'm trying to insert a node to a graph. I already have a function to find the maximum nodeID so the new nodeID is 1 greater than it but I'm having trouble getting the output as a graph.
newID :: Maybe NodeID -> NodeID
newID Nothing = 1
newID (Just x) = x+1
insertNode :: a -> Graph a -> Graph a
insertNode v (Graph node_list)=
let newNode=Node(newID(maxNodeID (Graph node_list))) v
in (node_list): [[(newNode,[])]]
Description for the graph is:
newtype Graph a = Graph [(Node a,[NodeID])]
deriving (Show,Eq)
type NodeID = Int
data Node a = Node { getNodeID :: NodeID,
getNodeVal :: a }
deriving (Show,Eq,Ord)
nodeA,nodeB,nodeC :: Node Char
nodeA = Node 0 'A'
nodeB = Node 1 'B'
nodeC = Node 2 'C'
exGraph :: Graph Char
exGraph = Graph [(nodeA,[1,2])
,(nodeB,[])
,(nodeC,[1,2])]
I've been stuck for this for 2 hours now. I just want to insert the new node at the end of the graph.
You're almost there, the only things you have to change are:
Use (++) :: [a] -> [a] -> [a] instead of (:) :: a -> [a] -> [a]. The : operator is for inserting things at the front, for adding to the end of a list the simplest way is to use the form xs ++ [x].
Wrap the result in a Graph constructor.
So a working version is:
insertNode :: a -> Graph a -> Graph a
insertNode v (Graph node_list)=
let newNode=Node(newID(maxNodeID (Graph node_list))) v
in Graph (node_list ++ [(newNode,[])])
Related
I'm almost there with this code the only difference is instead to adding n1 to the graph, I have to add the edges of n1 to the graph but I can't seem to figure out how.
Question: The file includes a function named insertEdge of type Eq a =>
(NodeID,NodeID) -> Graph a -> Maybe (Graph a) that inserts an
edge from the Node with the given NodeID in the first part of the tuple
to the Node with the given NodeID in the second part of the tuple.
If the edge already exists, it should NOT introduce a duplicate. If
the nodes corresponding to either of the given NodeIDs do not already
exist, the function should return Nothing.
`insertEdge :: Eq a => (NodeID,NodeID) -> Graph a -> Maybe (Graph a)
insertEdge _ (Graph []) = Nothing
insertEdge (n1,n2) g#(Graph graph)
| not containsBothNodes = Nothing
| otherwise = Just(Graph(insertE (n1,n2) graph))
where
containsBothNodes :: Bool
containsBothNodes = case(lookupNode n1 g) of
(Just _)->True
_ -> False
insertE (n1,n2) ((n0,es):graph)=
if (getNodeID n0)==n2
then
if es/=[]
then (n0,es):graph
**else (n0,es++[n1]):graph**
else (n0,es):insertE (n1,n2)graph
Description of the graph
newtype Graph a = Graph [(Node a,[NodeID])]
deriving (Show,Eq)
type NodeID = Int
data Node a = Node { getNodeID :: NodeID,
getNodeVal :: a }
deriving (Show,Eq,Ord)
nodeA,nodeB,nodeC :: Node Char
nodeA = Node 0 'A'
nodeB = Node 1 'B'
nodeC = Node 2 'C'
exGraph :: Graph Char
exGraph = Graph [(nodeA,[1,2])
,(nodeB,[])
,(nodeC,[1,2])]
`
I highlighted the part that I cannot figure out. Instead of adding n1, it should add the edges of n1
I am trying to add an edge to a graph in Haskell where the graph data type is defined as:
data Graph a = Graph [(a, [a])]
deriving (Show)
Effectively, my data type is defined as: A Graph is a list of nodes stored as tuples, where the first element is the node value and the second element is a list of its edges (i.e., which other nodes it is connected to).
When inserting an edge between two nodes (u,v), you first have to check that both nodes exist and that the edge does not already exist. That is, that (u, [a,b...n]) and (v,[a,b...n]) their respective lists of edges does not contain u or v. Thus, I have two functions that performs this check. If this check passes and due to that my data type is defined as above mentioned, I must insert u and v in respective node's lists. After this, I must return a new Graph.
addEdge :: Eq a => Graph a -> (a, a) -> Graph a
addEdge g (u, v)
| (existsNode u g) && (existsNode v g) && (not (existsEdge (u, v) g)) = undefined
| otherwise = g
-- Check if an edge between two nodes exists
existsEdge :: Eq a => (a, a) -> Graph a -> Bool
existsEdge (u, v) g = elem u (getEdges (u, v) g) && elem v (getEdges (u, v) g)
getEdges :: Eq a => (a, a) -> Graph a -> [a]
getEdges (u, v) g =
let rightNeighbours = getNodeNeighbours (getNode u g)
leftNeihbours = getNodeNeighbours (getNode v g)
in rightNeighbours ++ leftNeihbours
-- Get a node given its node id
getNode :: Eq a => a -> Graph a -> (a, [a])
getNode y (Graph []) = (y, [])
getNode y (Graph (x : xs))
| y == fst x = x
| otherwise = getNode y (Graph xs)
I need a way to fill the part where undefined is now with something that takes each node u and v, and appends v to u's neighbors list (u,[v]) and vice versa (v, [u]), that results in returning a Graph.
For example, if we have that:
g = (Graph [(1,[2]),(2,[1]), (3,[2])])
And we want to add an edge between nodes 3 and 1. We first see that both nodes exist, and that an edge does not already exist -->
g = (Graph [(1,[2,3]),(2,[1]), (3,[2,1])])
Is there a way to do this in Haskell?
This is a nice example for a common rule of thumb:
Avoid boolean checks and then conditionally doing something. Instead write functions that attempt doing something, and fail if it's not possible.
Your task can be broken down to:
Pick out both of the nodes between which you want the edge (if they exist). You should do this in a way that allows also tweaking them, not just reading out.
Modify the edges-list of one of the nodes, inserting the new edge (if it doesn't exist).
The failure cases should be associated with a Maybe type: if an operation isn't possible, it's typically a bad idea to have it silently fail, instead you should make it clear that the update wasn't applied and then leave it to the caller to ignore it or do something else.
addEdge :: Eq a => Graph a -> (a, a) -> Maybe (Graph a)
Now, what do I mean by “do this in a way that allows also tweaking [the nodes]”? It means that you should return a view into the old version, as well as a function that, given a modified value of the node, reconstructs the corresponding modified version of the entire graph. Specifically, you want to modify the outgoing edges. (Modifying the node's key would require also updating all other nodes that may point to it; we don't need that.)
getNode :: Eq a => a -> Graph a -> Maybe ((a, [a]), [a] -> Graph a)
This signature looks a bit daunting; let's introduce some type synonyms to make it easier:
type Node a = (a, [a])
type NodeView a = (Node a, [a] -> Graph a)
getNode :: Eq a => a -> Graph a -> Maybe (NodeView a)
The main change in implementation is that you need to “remember” the nodes in the list that were skipped because they didn't match. I would do this with an auxiliary function
getNode' :: Eq a => a -> Graph a
-> [Node a] -- ^ The nodes that need to be prepended in the reconstructed graph
-> Maybe (NodeView a)
getNode' _ _ (Graph []) = Nothing -- Node was not found
getNode' y prep (Graph ((x,es):ns))
| x==y -- Node was found, now create a view to it:
= Just ( (x,es)
, \es' -> Graph $ prep ++ (x,es') : xs )
| otherwise -- Not found yet, but maybe later. Add currently tried node to the prep-list.
= getNode' y ((x,es):prep) (Graph ns)
Obs: the above makes a change to the reconstructed graph that may or may not matter for you. Can you spot what it is?
In practice, you shouldn't use getNode' directly, but always call it with empty prep list. In fact you should probably make it a local “loop body” function:
getNode :: Eq a => a -> Graph a -> Maybe (NodeView a)
getNode y = go y []
where go _ _ (Graph []) = Nothing
go y prep (Graph ((x,es):ns)) = ...
For the rest of the task, you can use the NodeView given by this function as a helper to create the whole updated graph.
I am trying to get my feet wet with Haskell and I have found a few workshop which asks to create a graph data structure. I followed along and created a Binary Tree using map which felt much simpler. I have the following data types given
type Graph a = [(Node a, Edges)]
type Edges = [NodeID]
type NodeID = Int
data Node a = Node
{ getNodeID :: NodeID,
getNodeVal :: a
}
deriving (Show, Eq)
and example node would be as follows
nodeA = Node 0 'A'
and an example graph connected both ways would be
graphA = [(nodeA, [1]), nodeB, [0]]
Now in order to do any kind of insert or remove operation, I would first have to find out what the max NodeID at the moment is. So I am trying to write a maxNodeID as follows
maxNodeID :: Graph a -> Maybe NodeID
maxNodeID [] = Nothing --base case
But I am having a real hard coming up with the next case for this function.
My type definition for insertNode function is as follows
insertNode :: a -> Graph a -> Graph a
-- This is my idea for a base case but I get a parse error at 0
insertNode v [] = [a, []] where a = Node {0, v}
Any help with this and creating a insertNode function would be much appreciated as it would really help me set myself in the right path.
Rather than rolling my own, I would use the maximumBy :: Foldable t => (a -> a -> Ordering) -> t a -> a functrion from Data.List.
maxNodeID :: Graph a -> Maybe NodeID
maxNodeID [] = Nothing --base case
maxNodeID xs = Just $ maximumBy (\a b -> compare (getID a) (getID b)) xs
where getID = getNodeID . fst
For your insertNode function you need
insertNode v [] = [(a, [])] where a = Node 0 v
-- or --
insertNode v [] = [(a, [])] where a = Node {getNodeID = 0, getNodeVal= v}
Edited to add:
If you are not comfortable with type classes yet, you can read the type of maximumBy specialized for Lists as :: (a -> a -> Ordering) -> [a] -> a.
I've just started to learn Haskell and for practice I've decided to create a function that takes a tree, whose elements have a position and size, and returns the element located at a certain position. My code looks like this:
import Data.List (dropWhile)
data Node = Node (Int,Int) (Int,Int) [Node] deriving(Eq, Show)
findNode :: (Int,Int) -> Node -> Maybe Node
findNode loc node#(Node (x, y) (width, height) []) = if loc >= (x, y) && loc <= (x+width, y+height) then Just node else Nothing
findNode loc node#(Node (x, y) (width, height) children) =
if loc >= (x, y) && loc <= (x+width, y+height)
then if not $ null nodes then
head nodes
else
Just node
else Nothing
where nodes = dropWhile (==Nothing) $ map (findNode loc) children
This code compiles and runs perfectly as far as I can tell, but I'm curious about one thing, Why is head nodes acceptable instead of Just $ head nodes?.
That's because your nodes has a type of [Maybe Node]. You can infact verify that by annotating it explicitly and compiling it again:
findNode loc node#(Node (x, y) (width, height) children) =
if loc >= (x, y) && loc <= (x+width, y+height)
then
if not $ null nodes
then head nodes
else Just node
else Nothing
where
nodes = dropWhile (==Nothing) $ map (findNode loc) children :: [Maybe Node]
So how does, nodes have [Maybe Node] type ?
The type of map (findNode loc) children is [Maybe Node]. (General type of map is map :: (a -> b) -> [a] -> [b] and in your case the type of findNode loc is Node -> Maybe Node and hence the resultant type is [Maybe Node] ). And the type of dropWhile is (a -> Bool) -> [a] -> [a]. In your case a already is Maybe Node and hence your nodes has a type of [Maybe Node].
I have this data type :
data Node a = Node
{ label :: a,
adjacent :: [(a,Int)] } deriving (Show, Eq)
data Network a = Graph [Node a] deriving (Show, Eq)
I have a function which turns a Graph to a list of nodes :
deGraph :: ([Node a] -> Network a) -> [Node a] -> [Node a]
deGraph _ x = x
for example :
Main> deGraph Graph [ ( Node 'a' [ ( 'b' , 3 ) , ( 'c' ,2 ) ] ) , ( Node 'b' [ ('c' , 3 ) ] ) , ( Node 'c' [] ) ]
[Node {label = 'a', adjacent = [('b',3),('c',2)]},Node {label = 'b', adjacent = [('c',3)]},Node {label = 'c', adjacent = []}]
But when I use the function inside a function like this :
func1 (Graph x) = deGraph (Graph x)
I get this error :
ERROR "./Network.hs":14 - Type error in application
* Expression : deGraph (Graph x)
Term : Graph x
Type : Network b
* Does not match : [Node a] -> Network a
Can you tell me how can I solve this problem?
Your deGraph function has two arguments and simply returns the second of the two.
You probably want this instead:
deGraph :: Network a -> [Node a]
deGraph (Graph x) = x
The call to deGraph in GHCi works because you forgot to put parentheses around Graph and the following list, so it's also a call with two arguments. In func1, you (correctly) use parentheses, but then get a type error, because you're inconsistent.
Simply make Graph a record, too:
data Network a = Graph { nodes :: [Node a] } deriving (Show, Eq)
Then nodes has type Network a -> [Node a], and can be called like
Main> nodes $ Graph listOfNodes