简体   繁体   English

在Haskell中是否可以将putStrLn函数应用于字符串列表的每个元素,使其打印到屏幕上,而无需递归

[英]Is it possible in Haskell to apply the function putStrLn to every element of a list of Strings, have it print to the screen, while being non recursive

I am trying to make a function that takes a list of strings and executes the command putStrLn or print (I think they are basically equivalent, please correct me if I am wrong as I'm still new to Haskell) to every element and have it printed out on my terminal screen. 我正在尝试制作一个包含字符串列表并执行命令putStrLnprint的函数(我认为它们基本上是等效的,如果我错了,因为我还是Haskell的新手,请更正我)对每个元素都有打印在我的终端屏幕上。 I was experimenting with the map function and also with lambda/anonymous functions as I already know how to do this recursively but wanted to try a more complex non recursive version. 我正在尝试使用map函数以及lambda / anonymous函数,因为我已经知道如何递归执行此操作,但是想尝试一个更复杂的非递归版本。 map returned a list of the type IO() which was not what I was going for and my attempts at lambda functions did not go according to plan. map返回的列表类型不是我想要的IO(),而我对lambda函数的尝试未按计划进行。 The basic code was: 基本代码是:

test :: [String] -> something
test x = map (\a->putStrLn a) x -- output for this function would have to be [IO()]

Not entirely sure what the output of the function was supposed to be either which also gave me issues. 不完全确定该函数的输出应该是哪个,这也给我带来了问题。

I was thinking of making a temp :: String variable and have each String appended to temp and then putStrLn temp but was not sure how to do that entirely. 我当时正在考虑制作一个temp :: String变量,并将每个String附加到temp上,然后将putStrLn temp附加上,但是不确定如何完全做到这一点。 I though using where would be viable but I still ran into issues. 我虽然使用where将可行的,但我还是遇到了问题。 I know how to do this in languages like java and C but I am still quite new to Haskell. 我知道如何使用Java和C这样的语言来执行此操作,但是对于Haskell还是很陌生。 Any help would be appreciated. 任何帮助,将不胜感激。

There is a special version of map that works with monadic functions, it's called mapM : 有一个特殊的map版本可以使用mapM函数,称为mapM

test :: [String] -> IO [()]
test x = mapM putStrLn x

Note that this way the return type of test is a list of units - that's because each call to putStrLn returns a unit, so result of applying it to each element in a list would be a list of units. 请注意,这种方式的test返回类型是单位列表-这是因为对putStrLn的每次调用putStrLn返回一个单位,因此将其应用于列表中的每个元素的结果将是单位列表。 If you'd rather not deal with this silliness and have the return type be a plain unit, use the special version mapM_ : 如果您不想处理这种愚蠢行为,并且将返回类型设置为简单单位,请使用特殊版本的mapM_

test :: [String] -> IO ()
test x = mapM_ putStrLn x

I was thinking of making a temp :: String variable and have each String appended to temp and then putStrLn temp 我当时正在考虑制作一个temp :: String变量,并将每个String附加到temp,然后放到putStrLn temp

Good idea. 好主意。 A pattern of "render the message" then a separate "emit the message" is often nice to have long term. 从长远来看,一种“呈现消息”然后一个单独的“发出消息”的模式通常很不错。

test xs = let temp = unlines (map show xs)
          in putStrLn temp

Or just 要不就

test xs = putStrLn (unlines (show <$> xs))

Or 要么

test = putStrLn . unlines . map show

Not entirely sure what the output of the function was supposed to be either which also gave me issues. 不完全确定该函数的输出应该是哪个,这也给我带来了问题。

Well you made a list of IO actions: 好了,您列出了IO操作的列表:

test :: [String] -> [IO ()]
test x = map (\a->putStrLn a) x

So with this list of IO actions when do you want to execute them? 因此,有了此IO操作列表,您什么时候想要执行它们? Now? 现在? Just once? 就一次? The first one many times the rest never? 第一个,其余的从来没有? In what order? 以什么顺序?

Presumably you want to execute them all now. 大概您想立即执行它们。 Let's also eta reduce (\\a -> putStrLn a) to just putStrLn since that means the same thing: 让我们也将eta (\\a -> putStrLn a) putStrLn因为那意味着同一件事:

test :: [String] -> IO ()
test x = sequence_ (map (\a->putStrLn a) x)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM