Laudosolis
Laudosolis

Reputation: 33

Constraining an argument to be an Int

I'm trying to declare a function where the numerical argument can only be an Int.

I'm writing a function that'll discard every nth element of a list. I'm using modulo arithmetic, but the mod function will only take a type of Int and I can't figure out how to guarantee my number will satisfy that.

My code is as follows:

dropEvery :: (Num n, Eq n) => n -> [a] -> [a]
dropEvery m list = [list !! i | i <- [1 .. length list], i `rem` m /= 0]

I've run :info mod and replaced Num n with Real n, Enum n and Integral n (all the constraints I can see in the output) but this still doesn't guarantee the compiler that n will be an Int.

I'm sure there are solutions to this problem which don't use such a imperative approach, but I'd like to use this opportunity to learn a bit more about how types and constraints work in Haskell by solving this problem head-on.

Upvotes: 2

Views: 69

Answers (1)

flawr
flawr

Reputation: 11628

You just have to use the actual type Int instead of using constrains (Num n, Eq n). (Note that Haskell uses 0-based list indexing so I had to add a -1 for it to work correctly.)

dropEvery :: Int -> [a] -> [a]
dropEvery m list = [list !! (i-1) | i <- [1 .. length list], i `rem` m /= 0]

main = print $ dropEvery 3 [1..20]

Try it online!

If you want to avoid the !! you can also avoid explicitly finding the length of the list by using zip which replaces your list comprehension with

[ l | (l,i) <- zip list [0..], (i+1) `rem` m /= 0]

Upvotes: 6

Related Questions