Haskell通过递归向列表中添加元素

Haskell通过递归向列表中添加元素,haskell,ghci,Haskell,Ghci,我试图理解Haskell中的列表,但我遇到了一些不确定的事情。是否可以通过循环进行迭代,并在每次迭代时向列表中添加一项?为了回答这个问题,我编写了以下代码: list = [] addNumbers 0 = return () addNumbers n = do print n n : list addNumbers (n-1) 我原以为这会起作用,但它似乎给出了错误“无法将类型“[]”与“IO”匹配”。我不太清楚为什么会出现这个错误,因为没有要求用户输入或输出。我认

我试图理解Haskell中的列表,但我遇到了一些不确定的事情。是否可以通过循环进行迭代,并在每次迭代时向列表中添加一项?为了回答这个问题,我编写了以下代码:

list = []
addNumbers 0 = return ()
addNumbers n =
 do
    print n
    n : list
    addNumbers (n-1)
我原以为这会起作用,但它似乎给出了错误“无法将类型“[]”与“IO”匹配”。我不太清楚为什么会出现这个错误,因为没有要求用户输入或输出。我认为这可能与“print n”有关,但如果没有这一行,它似乎不起作用


提前为任何帮助喝彩

这不会像您认为的那样,在Haskell中,一切都是不可变的(一旦给它一个值,该值就不能更改)。您可能想做的是:

addNumbers :: Int -> IO [Int]
addNumbers 0 = return []
addNumbers n = do print n
                  ns <- addNumbers (n-1)
                  return (n:ns)
注意
addNumbers
的签名,它接受
Int
并返回由IO monad封装的
Int
列表。它必须由IO monad封装,因为对打印的调用在IO monad中返回
()
,否则将无法打印该值

如果您只想在列表前面添加一个
Int
,那么您可以很容易地做到这一点

foo 0 = [0]
foo n = n:foo (n-1)

这不会像您认为的那样,在Haskell中,一切都是不可变的(一旦给它一个值,该值就不能更改)。您可能想做的是:

addNumbers :: Int -> IO [Int]
addNumbers 0 = return []
addNumbers n = do print n
                  ns <- addNumbers (n-1)
                  return (n:ns)
注意
addNumbers
的签名,它接受
Int
并返回由IO monad封装的
Int
列表。它必须由IO monad封装,因为对打印的调用在IO monad中返回
()
,否则将无法打印该值

如果您只想在列表前面添加一个
Int
,那么您可以很容易地做到这一点

foo 0 = [0]
foo n = n:foo (n-1)

通常在Haskell中,您会将数字的打印(不纯操作)与创建此类列表(纯操作)分开。如果您只是在调试print语句,那么可以使用类似Debug.Trace的东西来欺骗typechecker(同样,仅用于调试目的)。您正在将来自
print
IO
单子和列表单子混合在同一个绑定中!请记住,
a>=\a->
,因此它需要有非常特殊的类型。通常在Haskell中,您会将数字的打印(不纯操作)与创建这样的列表(纯操作)分开。如果您只是在调试print语句,那么可以使用类似Debug.Trace的东西来欺骗typechecker(同样,仅用于调试目的)。您正在将来自
print
IO
单子和列表单子混合在同一个绑定中!请记住
a>=\a->
,因此它需要有非常特殊的类型。我一直在玩这个,它工作得非常好。只是另一个小问题,我试图添加一个if语句。因此,如果这个数字可以被3整除,那么它就会被添加到列表中,如果不是的话,它只会拿走一个。它似乎不喜欢ns@Jordan将
返回(n:ns)
替换为
如果n`mod`3==0,则返回(n:ns)否则返回(tail ns)
。为此,您不需要在
if
下运行
addNumbers
。(注意,因为这可能会试图从空列表中删除一个元素)谢谢chi,有什么原因我不能在输出中调用“length”吗?我想这是一个列表。但是,如果我删除随机用户名代码中的打印并调用“length(addNumbers 3)”,则会出现错误。你知道吗?@Jordan你有一个类型不匹配:
length
有类型
[a]->Int
,但是你的列表有类型
IO[Int]
。试试
fmap length$addNumbers 3
。我一直在玩这个,它工作得很好。只是另一个小问题,我试图添加一个if语句。因此,如果这个数字可以被3整除,那么它就会被添加到列表中,如果不是的话,它只会拿走一个。它似乎不喜欢ns@Jordan将
返回(n:ns)
替换为
如果n`mod`3==0,则返回(n:ns)否则返回(tail ns)
。为此,您不需要在
if
下运行
addNumbers
。(注意,因为这可能会试图从空列表中删除一个元素)谢谢chi,有什么原因我不能在输出中调用“length”吗?我想这是一个列表。但是,如果我删除随机用户名代码中的打印并调用“length(addNumbers 3)”,则会出现错误。你知道吗?@Jordan你有一个类型不匹配:
length
有类型
[a]->Int
,但是你的列表有类型
IO[Int]
。请尝试
fmap length$addNumbers 3