我必须读
n
遍,然后将其全部放入列表中。我有以下代码,但它不起作用。任何 Haskell/函数专家可以给我一个启发吗?
replicateIO n a = do y <- a
if n < 0
then return []
else do ys <- (replicateIO n-1 a)
return [y:ys]
编译错误:
tres.hs:1:1: error:
Couldn't match type ‘(->) t0’ with ‘[]’
Expected type: t -> [[a]]
Actual type: t -> t0 -> [[a]]
|
1 | replicateIO n a = if n < 0 | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^...
这里有一些问题:
[y:ys]
写为 cons,但 Haskell 中的 cons 是 (:) :: a -> [a] -> [a]
运算符,所以它是 y : ys
,或 (y : ys)
(在括号之间)。如果你写 [y:ys]
,你就会将 (y:ys)
的结果包装成一个新的单例列表;y <- a
n+1 次,因为使用 Monad 的原因之一可能是使用 state(例如带有 IO
的机器状态),这可能会产生意想不到的副作用;和(replicateIO n-1 a)
,它在 Haskell 中被解释为 ((replicateIO n)-(1 a))
。但我认为最重要的方面是你用 Haskell 语法编写命令式程序。 Haskell 是一种“函数式”编程语言。这意味着不同的范式。我认为最好先编写一些不使用 monad 的程序(和 do
符号)。
话虽这么说,我们可以用上面的言论来解决问题中的问题:
replicateIO n a = if n < 0
then return []
else do y <- a
ys <- replicateIO (n-1) a
return (y:ys)
虽然这解决了问题,但它不是很优雅且Haskell
语法。例如,我们可以使用守卫代替 if
-
then
-else
:replicateIO n a | n < 0 = return []
| otherwise = do
y <- a
ys <- replicateIO (n-1) a
return (y:ys)
我们可以做一些进一步的改进(甚至省略
do
符号,但我认为首先认识到
do
实际上是某些函数的语法糖可能是有益的)。