执行单子计算N次。

3
我正在实现一个函数来执行一个单子计算N次。我已经编写了以下代码。
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)

我收到了以下错误信息。
• 264:44: 错误:
• 无法匹配类型 'm' 和 '[]'
'm' 是一个刚性类型变量,受到以下类型签名的限制:
performN :: forall (m :: * -> *) t. Monad m => Int -> m t -> m [t]
at :260:13
期望类型:[m t]
实际类型:m [t]
• 在 '(:)' 的第二个参数中,它是 'performN (n - 2) m'
在表达式中:(m : performN (n - 2) m)
在 'do' 块的语句中:
x2 <- if n == 1 then return [] else (m : performN (n - 2) m)
• 相关绑定包括
m :: m t(在 :262:12 绑定)
performN :: Int -> m t -> m [t](在 :261:1 绑定)

我似乎无法弄清楚我做错了什么以及如何修复它。

3
performN n-2 m 应该是 (performN n) - (2 m),而不是 performN (n - 2) m。修正后,您可能想要删除 m: 部分并改为减去一。虽然我猜您只是在练习,但这实际上是 replicateM - undefined
@Ryan 抱歉,我修改了问题。 - undefined
3个回答

9
你做了某件事零次正确。
performN :: Monad m => Int -> m t -> m [t]
performN 0 m = return []

现在你已经掌握了重复n次操作的第一步:先执行一遍。

performN n m = do
  x1 <- m

然后你只需要再做 n - 1 次就可以了,没有复杂的 if 判断。

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

该死!真不敢相信我当时在想什么。:| 谢谢!:) - undefined
3
使用applicatives:liftA2 (:) m (performN (n - 1) m) - undefined
2
等效地,(:) <$> m <*> performN (n - 1) 很不错,因为当 (<*>) 运算符可以隐式分组时,你不需要显式使用括号进行分组。而且,如果你使用 pure 而不是 return,你可以将其推广到 Applicative,而不仅仅要求 Monad。 - undefined
2
@amalloy: 当然,但如果我们要实际一点并且使用Applicative,那就只需要replicateM =) 请参考问题的评论。 - undefined

5
如果您需要使用此函数,而不是为了练习而需要实现它,您应该使用Control.Monad.replicateM而不是重新实现它。

4

太多的东西了。 n == 1n-2?为什么?更简单点!

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

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接