[Haskell-beginners] Help with meaningful error message...

Daniel Fischer daniel.is.fischer at googlemail.com
Wed Jun 8 00:31:36 CEST 2011


On Tuesday 07 June 2011, 23:54:18, Sean Charles wrote:
> On 07/06/11 22:50, aditya siram wrote:
> > I think the parse error is here:
> > 
> > forwardRoutes m [] = m
> > forwardRoutes m (row:rows) =
> > 
> >   case M.lookup m (row !! 0) of
> >   
> >     Just route ->  M.update m (row !! 1):route
> >     Nothing ->  M.insert from []
> >   
> >   forwardRoutes m rows<----------------- you probably want to remove
> >   this line
> 
> If I do that, how does my recursive function call itself again?
> 
> I think it is badly broken in the syntax!
> In the last five minutes I have progressed to ...
> 
> 
> forwardRoutes :: M.Map String [String] -> [Record] -> M.Map
> forwardRoutes m [] = m
> forwardRoutes m (row:rows) =
>    case M.lookup m (row !! 0) of
>      Just route -> M.update m (row !! 1):route
>      Nothing    -> M.insert (row!!0) []
>    forwardRoutes m rows
> 
> but I think it ought to be...
> 
> 
> forwardRoutes :: M.Map String [String] -> [Record] -> M.Map
> forwardRoutes m [] = m
> forwardRoutes m (row:rows) =
>    case M.lookup m (row !! 0) of
>      Just route -> forwardRoutes (M.update m (row !! 1):route) rows
>      Nothing    -> forwardRoutes (M.insert (row!!0) []) rows

Much closer. Now you have a recursion and it can be parsed. The error will 
now arise in type-checking.

You've flipped the arguments in the lookup.

In the `Just' case, (M.update m (row !! 1):route) is parsed as

(M.update m (row !! 1)) : route

which is a list, not a map. You'll need to parenthesize thus:
((row !! 1) : route)

However,

Prelude> :t Data.Map.update
Data.Map.update
  :: Ord k =>
     (a -> Maybe a) -> k -> Data.Map.Map k a -> Data.Map.Map k a

so there's more to change in that branch. It seems that if (row !! 0) is a 
key in the map, you want to modify the associated value by prepending
(row !! 1) to it. That would be achieved by

(M.update (\_ -> Just ((row !! 1):route)) (row !! 0) m)

But you don't use the value associated to the key here [you could, but 
you've already looked that up before], so update is probably the wrong 
function here, try

(M.insert (row !! 0) ((row !! 1) : route) m)

In the `Nothing' branch, you've omitted the map in which to insert.


forwardRoutes m (row@(h:t):rows) =
  case M.lookup h m of
    Just route -> forwardRoutes (M.insert h (head t:route) m) rows
    Nothing -> forwardRoutes (M.insert h [] m) rows

would do what I think you want.

But it'd better be written as a fold,

forwardRoutes m rows = Data.List.foldl' update1 m rows
-- you can leave off the arguments if you wish

Now, update1 is the single-row update function, e.g.

update1 m [] = m -- empty row, do nothing
update1 m (x:xs) =
  case M.lookup x m of
    Nothing -> M.insert x [] m
    Just route
      | null xs -> ? -- what then?
      | otherwise -> M.insert x (head xs:route) m



More information about the Beginners mailing list