2
votes

I'm implementing a function to perform a monadic computation N times. I've written the following code.

performN :: Monad m => Int -> m t -> m [t]
performN 0 m = return []
performN n m = 
  do x1<- m
     x2<- if n == 1 then return [] else (m:performN (n-2) m)
     return (x1:x2)

I get the following error.

:264:44: error:
• Couldn't match type ‘m’ with ‘[]’
‘m’ is a rigid type variable bound by
the type signature for:
performN :: forall (m :: * -> *) t. Monad m => Int -> m t -> m [t]
at :260:13
Expected type: [m t]
Actual type: m [t]
• In the second argument of ‘(:)’, namely ‘performN (n - 2) m’
In the expression: (m : performN (n - 2) m)
In a stmt of a 'do' block:
x2 <- if n == 1 then return [] else (m : performN (n - 2) m)
• Relevant bindings include
m :: m t (bound at :262:12)
performN :: Int -> m t -> m [t] (bound at :261:1)

I can't seem to figure out what I am doing wrong and how to fix it.

3
performN n-2 m is (performN n) - (2 m), not performN (n - 2) m. After fixing that, you'll probably want to drop the m: bit and change to subtracting one. And though I suppose you're doing this just as an exercise, it's replicateM.Ry-♦
@Ryan Sorry, edited the question.Abdul Fatir

3 Answers

8
votes

You've got doing something zero times right.

performN :: Monad m => Int -> m t -> m [t]
performN 0 m = return []

And you've got the first part of doing something n times right: do it once.

performN n m = do
  x1 <- m

But then all you have to do is do it n − 1 more times. No strange if stuff.

performN n m = do
  x1 <- m
  x2 <- performN (n - 1) m
  return (x1 : x2)
5
votes

If you need to use this function, rather than needing to implement it for practice, you should just use Control.Monad.replicateM instead of reimplementing it yourself.

4
votes

Too much stuff. n == 1? n-2? Why? Simpler!

performN :: Monad m => Int -> m t -> m [t]
performN 0 _ = return []
performN n m =
  do x  <- m
     xs <- performN (n-1) m
     return $ x:xs