迭代打印列表中的每个整数 [英] Iteratively printing every integer in a List
问题描述
假设我有一个整数列表 l = [1,2]
我想打印to stdout
。
执行 print l
产生 [1,2]
假设我想打印没有花括号的列表
map print l
产生 (显示(IO()))
在一个交互式GHCi命令中添加一个实例声明:print它
`:t print
print :: Show a => a - > IO()
所以,当我认为这会起作用时,我继续尝试:
map putStr $ map show l
由于我怀疑从Integer到String的类型不匹配是怪罪。这产生了与上面相同的错误信息。
我意识到我可以做一些事情,比如将列表连接成一个字符串,但是我希望尽可能避免这种情况。 / p>
发生了什么事?我怎样才能做到这一点,而不需要从List的元素构造一个字符串?
假设给出了一个 xs :: [a]
和函数 f :: Monad m => a - > m b
。您希望将函数 f
应用于 xs
的每个元素,生成一系列操作,然后对这些操作进行排序。下面是我将如何构建一个函数,将其称为 mapM
,这是做到这一点的。在基本情况下, xs = []
是空列表,我们只返回 []
。在递归的情况下, xs
的形式为 x:xs
。首先,我们要将 f
应用于 x
,给出动作 fx :: mb
。接下来,我们要在 xs
上递归调用 mapM
。执行第一步的结果是一个值,比如 y
;执行第二步的结果是一个值列表,比如 ys
。因此,我们将 y
和 ys
收集到一个列表中,然后将它们返回到monad中:
mapM :: Monad m => (a - > m b) - > [a] - > m [b]
mapM f [] = return []
mapM f(x:xs)= f x>> = \ y - > mapMf ys>> = \ s - >返回(y:ys)
现在我们可以映射一个像 print
,它在 IO
monad中返回一个动作,并在要打印的值列表中: mapM print [1..10 ]
正好是从1到10的整数列表。然而,存在一个问题:我们并不特别关心收集印刷操作的结果;我们主要关心他们的副作用。而不是返回 y:ys
,我们只需返回()
。
mapM_ :: Monad m => (a - > m b) - > [a] - > m()
mapM_ f [] = return()
mapM_ f(x:xs)= f x>> mapM_ f xs
请注意 mapM
和<可以使用序列
和序列_
定义code> mapM _ 标准库中的函数,这些函数正是他们的名字所暗示的。如果您查看 Control.Monad $中的
mapM
和 mapM _
的源代码c $ c>,你会看到它们以这种方式实现。
Say I have a List of integers l = [1,2]
Which I want to print to stdout
.
Doing print l
produces [1,2]
Say I want to print the list without the braces
map print l
produces
No instance for (Show (IO ())) arising from a use of `print'
Possible fix: add an instance declaration for (Show (IO ()))
In a stmt of an interactive GHCi command: print it
`:t print
print :: Show a => a -> IO ()
So while I thought this would work I went ahead and tried:
map putStr $ map show l
Since I suspected a type mismatch from Integer to String was to blame. This produced the same error message as above.
I realize that I could do something like concatenating the list into a string, but I would like to avoid that if possible.
What's going on? How can I do this without constructing a string from the elements of the List?
Suppose you're given a list xs :: [a]
and function f :: Monad m => a -> m b
. You want to apply the function f
to each element of xs
, yielding a list of actions, then sequence these actions. Here is how I would go about constructing a function, call it mapM
, that does this. In the base case, xs = []
is the empty list, and we simply return []
. In the recursive case, xs
has the form x : xs
. First, we want to apply f
to x
, giving the action f x :: m b
. Next, we want recursively call mapM
on xs
. The result of performing the first step is a value, say y
; the result of performing the second step is a list of values, say ys
. So we collect y
and ys
into a list, then return them in the monad:
mapM :: Monad m => (a -> m b) -> [a] -> m [b]
mapM f [] = return []
mapM f (x : xs) = f x >>= \y -> mapM f ys >>= \ys -> return (y : ys)
Now we can map a function like print
, which returns an action in the IO
monad, over a list of values to print: mapM print [1..10]
does precisely this for the list of integers from one through ten. There is a problem, however: we aren't particularly concerned about collecting the results of printing operations; we're primarily concerned about their side effects. Instead of returning y : ys
, we simply return ()
.
mapM_ :: Monad m => (a -> m b) ->[a] -> m ()
mapM_ f [] = return ()
mapM_ f (x : xs) = f x >> mapM_ f xs
Note that mapM
and mapM_
can be defined without explicit recursion using the sequence
and sequence_
functions from the standard library, which do precisely what their names imply. If you look at the source code for mapM
and mapM_
in Control.Monad
, you will see them implemented that way.
这篇关于迭代打印列表中的每个整数的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!