0

I just started using Haskell some weeks ago and I lack of imagination to resolve a function in this situation.

So I am trying to find the predecessors of a vertex in a graph implemented in Haskell.

My graph :

-- | A directed graph
data Graph v = Graph
    { arcsMap :: Map v [v]     -- A map associating a vertex with its successors
    , labelMap :: Map v String -- The Graphviz label of each node
    , styleMap :: Map v String -- The Graphviz style of each node
    }

The function successors :

-- | Returns the successors of a vertex in a graph in ascending order
--
-- We say that `v` is a successor of `u` in a graph `G` if the arc `(u,v)`
-- belongs to `G`.
-- Note: Returns the empty list if the vertex does not belong to the graph.
successors :: Ord v => v -> Graph v -> [v]
successors v (Graph arcs _ _) = findWithDefault [] v arcs

And the function I'm currently trying to resolve :

-- | Returns the predecessors of a vertex in a graph in ascending order
--
-- We say that `u` is a predecessor of `v` in a graph `G` if the arc `(u,v)`
-- belongs to `G`.
-- Note: Returns the empty list if the vertex does not belong to the graph.
predecessors :: Ord v => v -> Graph v -> [v]
predecessors v  (Graph arcs _ _) = 
     map (fst)  (filter (\(x,[y]) -> elem v [y]) (assocs arcs) ) 

I need to find a way to get the keys (the vertices) by having the value (the successor) of those vertices. For example :

-- >>> predecessors 3 $ addArcs emptyGraph [(1,2),(2,3),(1,3)]
-- [1,2]

But when I run that line, I get Non-exhaustive patterns in lambda.

What is that and how can I fix it? Thank you!

  • Edit : Never mind I corrected it but I still do not really understand how haha
Velyyn S
  • 89
  • 6
  • 1
    You may need to use `assocs` function change the `Map` to list of key/value list and then find second element of the pair. just a hint like: `map fst . filter ((== 3) . snd)` – assembly.jc Oct 07 '19 at 04:34
  • Ahhh i just found the assocs function : O(n). Return all key/value pairs in the map in ascending key order. But i'm not used to the . thing, I can't visualize it yet. – Velyyn S Oct 07 '19 at 05:03
  • @assembly.jc I tried this but my syntax is obviously wrong `predecessors v (Graph arcs _ _) = map (fst) ( filter (snd==v) (assocs arcs) ) ` – Velyyn S Oct 07 '19 at 05:28
  • `snd` is a function and cannot use to compare the value `v` immediately, it need to composed with function `(== v)` like ((== v) . snd). or lambda form `(\p-> snd p == v)` – assembly.jc Oct 07 '19 at 05:43
  • @assembly.jc This function has compiled :`predecessors v (Graph arcs _ _) = map (fst) (filter (\(x,[y]) -> elem v [y]) (assocs arcs) ) ` But when i try to run `predecessors 3 $ addArcs emptyGraph [(1,2),(2,3),(1,3)]` It tells me : Non-exhaustive patterns in lambda – Velyyn S Oct 07 '19 at 05:54

1 Answers1

2

Haskell's Maps and Hashmap don't have efficient key lookups. The best you can do is O(n), and you have to write it yourself. I have something like this in my projects, which we can edit a bit to find all keys:

lookupKey :: Eq v => v -> Map.Map k v -> [k]
lookupKey val = Map.foldrWithKey go [] where
  go key value found =
    if value == val
    then key:found
    else found

You might want to use strict folds if you use strict maps.

Evg
  • 2,978
  • 5
  • 43
  • 58
MorJ
  • 566
  • 4
  • 14