抱歉,如果我很傻,但我是 Haskell 的初学者,我正在尝试用 putStrLn 打印列表,但我不知道如何解决下一个问题:
我正在尝试使用以下代码在 Haskell 中制作一个基本的打印列表:
import System.IO
array = map show [1, 2, 3, 4]
main :: IO ()
main = do
map putStrLn array
但是编译器给了我:
8 main.hs:7:3: error:
7 • Couldn't match expected type ‘IO ()’ with actual type ‘[IO ()]’
6 • In a stmt of a 'do' block: map putStrLn array
5 In the expression: do map putStrLn array
4 In an equation for ‘main’: main = do map putStrLn array
我该如何解决?
Haskell 处理 IO 的方式与其他语言截然不同。
在像 Java 这样的语言中,
System.Out.println(3)
是一个不会求值的语句,所以你甚至不能写像 x = System.Out.println(3);
这样的东西。
在像 Lisp 这样的语言中,
(print 3)
计算结果为 3,并且在计算过程中打印 3
。因此,说出类似 (setq x (print 3))
的内容会将 x
的值设置为 3
并打印 3
。
在 Haskell 中,
putStrLn "3"
表示打印 3
的命令。因此,说 x = putStrLn "3"
除了将 x
分配给命令 putStrLn "3"
之外,绝对没有任何作用。
让我们看看一些类型。我们有
map :: (a -> b) -> [a] -> [b]
putStrLn :: String -> IO ()
因此,我们应该有
map putStrLn :: [String] -> [IO ()]
map putStrLn array :: [IO ()]
换句话说,
map putStrLn array
是一个“IO操作”列表,它会产生()
类型的值(基本上,这意味着执行操作不会产生额外的信息)。
但是,为了写
main :: IO ()
main = map putStrLn array
这是什么
main :: IO ()
main = do map putStrLn array
翻译为,我们需要
map putStrLn
为 IO ()
类型,而不是 [IO ()]
类型。
如果您希望对列表中的每个元素执行操作,可以使用
for_
函数,其类型为 for_ :: (Foldable g, Applicative f) => g a -> (a -> f ()) -> f ()
。 IO
是 Applicative
并且 []
是 Foldable
,所以特别是 for_ :: [String] -> (String -> IO ()) -> IO ()
是 for_
可以采用的一种类型。代码看起来像
import Data.Foldable (for_)
array :: [String]
array = map show [1, 2, 3, 4]
main :: IO ()
main = for_ array putStrLn
这在命令式语言中相当于
for each x in array do {
putStrLn x;
}
main
需要IO
单子,因此您需要在IO
单子内部进行映射,而不是错误所述的List of IO
。 mapM_
可以完成这项工作。 mapM_
吃单子函数和某些东西的列表,它映射到单子内部。打印字符串时,结果将是 IO ()
。
array = map show [1, 2, 3, 4]
main :: IO ()
main = do
mapM_ putStrLn array
这是结果:
1
2
3
4