Ulrar
Ulrar

Reputation: 983

How to guard this case

I have this function to try and "register" matches in a list of lists :

processMatch :: String -> POSIXTime -> [[(String, POSIXTime)]] -> [[(String, POSIXTime)]]
processMatch host time hostList =
case hostList of
  []                 -> [[(host, time)]]
  ((host, t):x):tail -> ((host, t):(host, time):x):tail
  x:t                -> x:(processMatch host time t)

The problem with this is that host is re-declared with a new value, instead of being a condition. So whatever host matches, I end up just adding it to the first matche's list. I imagine I need to use a guard instead, but I can't figure out how to deconstruct my lists like that in a guard, is it even possible ?

I could just do it another way with a few conditions but I'm curious to know if it's even possible to do it simply like that. Thanks !

Upvotes: 0

Views: 43

Answers (1)

chepner
chepner

Reputation: 530823

I would start by defining a helper function that closes over host and time. Along side that, you can name the pair (host, time) as it will be used in two different places in the definition of the helper.

The helper uses a case expression to pattern-match only the head of an inner list, rather than trying to match the entire host list.

In the pattern that matches a host/time pair, you need to use a separate variable to capture the existing host, then compare that to host in a guard. You can only match literals directly in a pattern

processMatch :: String -> POSIXTime -> [[(String, POSIXTime)]] -> [[(String, POSIXTime)]]
processmatch host time lst = go lst
    where newPair = (host, time)
          go [] = [[newPair]]
          go (head:tail) = case head of
                            (h,t):rest | h == host ->((h,t):newPair:rest):tail
                            otherwise -> head : go tail

As an aside, a previous typo used an undefined name first, which came from an at-pattern in a previous version of the answer. It's probably actually worth using, but I'll mention here rather than edit the main answer:

first@(h,_):rest | h == host -> (first:newPair:rest):tail

This accomplishes two things: 1) it avoids the repetition of (h,t) on both sides; 2) it avoids giving a name to the matched time, which you don't really care about as long as you have first to refer to the pair itself.

Upvotes: 3

Related Questions