List 将列表的每个元素复制到另一个元素的代码运行时不会出错,但不会执行任何操作

List 将列表的每个元素复制到另一个元素的代码运行时不会出错,但不会执行任何操作,list,haskell,printing,List,Haskell,Printing,我正在努力学习哈斯克尔。在下面的代码中,我尝试通过自己的函数将列表中的每个元素复制到另一个元素,然后尝试打印新列表 orilist = ["a", "b", "c"] mylist = [] addfn ss = do -- trying to add sent string ss to mylist let mylist = ss:mylist return () main = do mapM_ addfn orilist -- trying to se

我正在努力学习哈斯克尔。在下面的代码中,我尝试通过自己的函数将列表中的每个元素复制到另一个元素,然后尝试打印新列表

orilist =  ["a", "b", "c"]
mylist = []
addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()
main = do 
    mapM_ addfn orilist     -- trying to send each element of orilist to addfn
    mapM_ putStrLn mylist   -- trying to print each element of mylist 
    return ()       -- no error but nothing is printed
代码运行时没有任何错误,但没有打印任何内容。问题在哪里?谢谢你的帮助

addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()
这将本地绑定
mylist
定义为无限列表
ss:ss:ss:…
。然后,它没有被使用,所以这个定义是不相关的。因此,该代码相当于:

addfn ss = return ()
addfn _ = return ()
这是禁止的

Haskell不是命令式语言。您可能正试图修改全局变量
mylist
,但这是不可能的。一旦定义了
mylist=[]
,它将永远是
[]

您可以这样做:

orilist =  ["a", "b", "c"]

main = do 
    let mylist = orilist
    mapM_ putStrLn mylist   -- trying to print each element of mylist
甚至

orilist =  ["a", "b", "c"]

main = mapM_ putStrLn orilist

另一个例子:假设我们想要以一个空列表开始,并将其反转10次并追加其长度。我们可以使用递归按如下方式执行此操作:

doOnce oldList = reverse oldList ++ [length oldList]

newList = go 0 []
   where go 10 list = list
         go n list = go (n+1) (reverse list ++ [length list])

这是非常低效的,但我希望您能理解。

您的
addfn
不会做任何事情,它只返回一个单位
()
。实际上,您的
addfn
功能:

addfn ss = do   -- trying to add sent string ss to mylist
    let mylist = ss:mylist
    return ()
相当于:

addfn ss = return ()
addfn _ = return ()
因为您从未使用过mylist。如果您使用
mylist
,它将是一个无限列表,其中包含
[ss,ss,…]

在Haskell中没有赋值:您没有给变量赋值,而是声明了一个变量。一旦一个变量有了一个值,你就永远不能改变这个值。因此,即使前面有一个名为
mylist
的变量,它也不会使用该变量

使用
mapM\uuuaddfn orilist
后,每个
addfn
都将返回
()
,并且没有更改任何内容的状态,因此列表保持为空

在中,您希望读取每个文件的第一行。您可以这样做,例如编写一个函数来读取文件的第一行:

import System.IO(IOMode(ReadMode), withFile, hGetLine)

readFirstLine :: FilePath -> IO String
readFirstLine fp = withFile fp ReadMode hGetLine
然后,我们可以获得文件的第一行列表,例如:

main :: IO ()
main = do
    d <- mapM readFirstLine ["foo.txt", "bar.txt"]
    print d
main::IO()
main=do

d mylist os a function,addfn中的let隐藏而不是覆盖它,但是如果我忽略了
let
,则会出现错误。解决方案是什么?你不能像你假设的那样在Haskell中就地更新变量。所有“变量”都是常量和不可变的。当你说
myList=[]
时,整个程序就是这样。在Haskell中,一切都是不可变的,因此你不能向列表中添加任何内容。你似乎是一个Haskell初学者。在提出像这样的问题之前,我建议大家先把书读完。这个问题是关于Haskell中的一个基本概念,你要问的是LYAH几乎立即涵盖了哪些内容。我如何创建一个空列表,然后填充它?是否不可能创建一个空列表,然后填充它?如何动态创建列表?@mso这是不可能的,一个空列表一旦创建就会保持为空。您可以做的是创建一个已经填充的列表。或者,最多创建一个空列表,然后使用该值计算另一个列表(2),然后使用该值创建另一个列表(3),依此类推。但是在任何时候,你都不会“修改”原来的空列表,而是创建新的空列表。这在计算上不是很昂贵吗?你能在上面的答案中把这句话写进代码吗?@rnso Haskell如果使用得当,可能会很有效,但如果你是初学者,我建议你先不要考虑效率,而是学习这门语言。在您的示例中,您没有“将第一行添加到列表”,而是“创建一个包含第一行文件的列表”。不要从状态的角度思考,要从结果的角度思考。无论如何,我创建了一个(效率低下的)示例,只是为了说明您可以执行“循环修改列表”,而无需实际修改任何内容。好的。因此,创建一个函数来读取一行,然后使用mapM从不同的文件中获取行列表。@mso:的确,这就是
main
的思想。