Jon Harper
Jon Harper

Reputation: 105

How to count number of times guard statement happens in recursion?

I'm new to haskell and I got stuck in a little program I tried to make. I want to count number of times my guard statement goes through in all recursion rounds and then return that as Int. For example if c1 is 'a', c2 is 'b', g is 2 and s is "aaabbb" then returned int would be 2, because my guard statement is true in 2 cases.

I tried to make variable x and then add x + 1 to it every time guard statement happens. That didn't work because I learnt that in Haskell variable you set is always static so for example setting x = 0 at start would set that x to 0 every recursion round.

Here's my code:

gaps :: (Char, Char) -> Int -> String -> Int
gaps (c1,c2) g (s:xs)
   | c1 == s && c2 == (s:xs) !! g = --Count how many times this statement happens --
   | otherwise =  gaps (c1,c2) g xs

Upvotes: 2

Views: 157

Answers (2)

L0neGamer
L0neGamer

Reputation: 275

Off the back of questions on how to make this thing safer, I have made the following code snippet, borrowing from Ismor's answer.

-- a way to safely get the nth item from a list
get' :: [a] -> Int -> Maybe a
get' [] _ = Nothing
get' (x:xs) 0 = Just x
get' (x:xs) n 
 | n > 0 = get' xs (n-1)
 | otherwise = Nothing

-- takes a Maybe value. if it's Nothing, return 0. if it's Just a value, compare
-- the value and a given param, if equal return 1, else 0
seeEqual:: (Num b, Eq a) => Maybe a -> a -> b
seeEqual Nothing _ = 0
seeEqual (Just a) b
 | a==b = 1
 | otherwise = 0

-- I have edited the first guard so that it checks c1 and s, then tries to calculate
-- whether c2 and the specific list item are equal, and then recurses as before
gaps :: (Char, Char) -> Int -> String -> Int 
gaps _ _ [] = 0 -- base case 
gaps (c1,c2) g (s:xs) 
 | c1 == s = (seeEqual (get' (s:xs) g) c2) + gaps (c1,c2) g xs -- add one to final result 
 | otherwise = gaps (c1,c2) g xs

I do not claim that this is perfect, but I do think this is safe and shouldn't throw any exceptions or raise any errors.

Prelude> gaps ('a','b') 3 "aaaababbb"
3
Prelude> gaps ('a','b') 3 "aaaabbabb"
2

Upvotes: 1

lsmor
lsmor

Reputation: 5063

Just add 1 and call the function recursively

gaps :: (Char, Char) -> Int -> String -> Int
gaps _ _ [] = 0                                           -- base case 
gaps (c1,c2) g (s:xs)
   | c1 == s && c2 == (s:xs) !! g = 1 + gaps (c1,c2) g xs -- add one to final result
   | otherwise =  gaps (c1,c2) g xs

> gaps ('a','b') 2 "aaabbb"
2
> gaps ('a','b') 3 "aaaabbbb"
3

Be carefull when using !!. It isn't total and might fail if your input string has c1's values less than g positions before the end of the string

> gaps ('a','b') 3 "aaaababbb" -- doesn't fail
3
> gaps ('a','b') 3 "aaaabbabb" -- does fail!!!!

Upvotes: 5

Related Questions