Not as far as I know. You have to write a graph-traversing function.
First, decide where to break the circularity. In this case it is trivial: use the node names (assuming they are unique within a graph). For a more complex structure, such as a graph with nodes and edges as separate types, you would have to decide whether to store edges with nodes, nodes with edges, or keep nodes and edges completely separate.
Then enumerate all the nodes in the graph. In this case the obvious way is to traverse the graph collecting nodes in a finite map (see Data.Map). Then store each node as a name followed by a list of other node names.
Recovering the graph means using the "tying the knot" pattern. Read the stored graph into a structure of [(String, [String])]. Then the original graph can be reconstructed with the following code:
import qualified Data.Map as M
data Node = Node String [Node]
instance Show Node where
show (Node name others) = "Node " ++ show name ++
" " ++ show (map nodeName others)
where nodeName (Node n _) = n
restoreGraph :: [(String, [String])] -> M.Map String Node
restoreGraph pairs = table
where
table = M.fromList $ map makeNode pairs
makeNode (name, others) = (name, Node name $ map findNode others)
findNode str = fromJust $ M.lookup str table
Note the mutual recursion: table calls makeNode, which calls findNode, which calls table. Thanks to lazy evaluation this does the Right Thing.
Edit: code now tested and slightly expanded.