Given I have the following code:
data Note = C | Db | D | Eb | E | F | Gb | G | Ab | A | Bb | B
deriving (Show, Eq, Ord, Enum)
next :: Note -> Note
next B = C
next n = succ n
previous :: Note -> Note
previous C = B
previous n = pred n
resolveAscendingInterval :: Int -> Note -> Note
resolveAscendingInterval 0 note = note
resolveAscendingInterval interval note = resolveAscendingInterval (interval -1) (next note)
resolveDescendingInterval :: Int -> Note -> Note
resolveDescendingInterval 0 note = note
resolveDescendingIInterval interval note = resolveDescendingIInterval (interval -1) (previous note)
main :: IO ()
main = do
print $ resolveAscendingInterval 3 C
print $ resolveDescendingInterval 3 C
resolveAscendingInterval works fine, but when I run resolveDescendingInterval I get:
Non-exhaustive patterns in function resolveDescendingInterval
Their code and logic are very similar, so I don't have a clue of whats wrong
Another thing: Is there another way to achieve this behavior without recursion?
This is just a typo. Notice
resolveDescendingIInterval
is a different function fromresolveDescendingInterval
. Get rid of that extraI
.EDIT: Consider the following slightly unsafe code:
This is a partial function - it will fail when the interval is too large and we call
toEnum
on something out of range. You can clamp the range via code such asmax (fromEnum (minBound :: Note)) . min (fromEnum (maxBound :: Note))
. But there's probably a smarter way I'm just not thinking off immediately.One alternative would be to clamp the
interval
viarem interval (fromEnum note)
but then you'll need to handle the case when note is minBound separately.