gpt4 book ai didi

haskell - 无法在文件夹中执行 I/O?

转载 作者:行者123 更新时间:2023-12-03 13:43:26 26 4
gpt4 key购买 nike

我有一个 Data.Map映射 String 的结构转至 Strings s。无论出于何种原因,我想以 key: value 格式打印 map 的内容使用 foldrWithKey ,像这样:

M.foldrWithKey (\k v b -> putStrLn (k++": "++v++"\n")) (return ()) data

但是,只有 map 的第一个元素出现在输出中(即使 map 有多个元素)。但是当我尝试使用 foldrWithKey 构建列表时然后打印它,所有元素都显示出来:
print (M.foldrWithKey (\k v b -> k:b) [] data)

那么,为什么在尝试执行 I/O 时其他元素没有出现?是 foldr 的工作方式还是我遗漏了一些与惰性 io 相关的微妙怪癖?

最佳答案

这是因为正确的折叠是如何工作的,是的。折叠函数是一种累加:在每一步,给定一个元素(在本例中为键和值)和其余数据的累加结果,它将它们组合成一个结果。折叠作为一个整体递归地总结整个数据集。

在您的情况下,您将丢弃累加器函数的“结果”输入——请注意,从未使用过 b 参数。请记住, IO a 不仅仅是 a 类型的值,附加了一些额外的垃圾,它实际上代表的是产生 a 的计算,并且该计算只能通过将其与其他计算结合作为最终的一部分来运行main 函数的值(或者,在 GHCi 中,被评估的表达式的值)。

通过丢弃累积值,其他计算永远不会成为最终结果的一部分,因此这些值永远不会被打印出来。

从您提出问题的方式来看,我猜您在命令式编程中仍然比 Haskell 的函数式编程更舒服。显然,在某种有意义的意义上,在折叠期间打印实际上“发生”的命令式语言中,假设累积值是无用的是合理的。如果有帮助,请将此更多地视为一种元编程;您实际上并没有编写循环来打印值,而是构建了一个执行实际打印的命令式程序,并且通过丢弃累积的值,您基本上丢弃了展开循环的第一行以外的所有内容,以滥用比喻不好。

无论如何,在这种情况下,您可能想要的是执行“打印其余数据”操作,即 b 参数,并使用 putStrLn ... 将其与 (>>) 操作结合起来,该操作符基本上意味着“执行第一个操作,忽略结果,执行第二个”。这是对命令式“循环打印语句”的非常直接的翻译。

此外,虽然我理解这完全是题外话,但我可能会避免以这种方式混合格式和打印。在我看来,将每个键/值对分别格式化为一个列表似乎更整洁,然后再将其设置为 mapM_ putStrLn
mapM_ 是一个高阶函数,描述了你在这里所做的事情的本质;给定一个 a 类型的列表和一个将 a 转换为某种 IO Action 的函数,它将函数应用于每个项目并按顺序运行生成的 Action 列表。 mapM_ 的类型为 Monad m => (a -> m b) -> [a] -> m () ,一开始看起来很神秘,但 Haskell 的优点之一是,一旦你习惯阅读类型签名, mapM_ 的类型不仅一眼就能理解,它几乎是自我记录的,因为只有对于具有该类型的函数来说,这是一件明智的事情,而这正是 mapM_ 本身所做的。

关于haskell - 无法在文件夹中执行 I/O?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/6023237/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com