accumulating/iterating 递归和 IO 操作在类型 'IO a' 中的本质是什么?
What is the nature of accumulating/iterating recursively and IO operations within a function of type 'IO a'?
...假设 a
是某种类型,例如[Int],我们想要迭代,例如获取所有元素,对它们进行操作并在操作后打印结果,如操作发生在以下代码中:
fa :: [Int] -> [Int]
fa [] = []
fa (n:rln) = (n + 1) : fa rln
...但是在函数类型中
fb :: [Int] -> IO [Int]
...这样
main :: IO ()
main =
do
fb [3, 2, 6, 8] >>= print
...将按顺序打印给定列表 ([4, 3, 7, 9]) 并再次打印结果。
分化和背景
我想了解类型的本质'IO a'。
这个问题不是关于如何迭代折叠和 fmap 等现成函数的问题。
这不是打印和return相同结果是否有意义的问题。
到目前为止的代码
到目前为止,我已经得到了这个“野兽”:
f :: [Int] -> IO [Int]
f ln = f' ln >>= print >>= return (f' ln)
where
f' :: [Int] -> IO [Int]
f' [] = return []
f' (n:rln) = f' rln >>= (\r -> return ((n + 1) : r))
...可以像这样在 main 中应用
main :: IO ()
main = f [3, 2, 6, 8] >>= (putStrLn . (\r -> "result=" ++ show r))
...打印:
[4,3,7,9]
result=[4,3,7,9]
对我来说,可疑的是行 f ln = f' ln >>= print >>= return (f' ln)
没有将 f' ln
的结果传递给 return。
问题
类型的本质是什么IO a
?
特别是:
IO a
类型的函数总是 return
类型 a
的说法正确吗?
- 正如我们所见,我们可以在
IO a
类型的函数中执行 IO ()
操作 - 但是如果我们在这样的函数中打印,我们真的需要这么笨拙的代码吗?
- 最有效的实施方式是什么?
- 我们通常应该避免在一个函数中双重使用(IO 操作和递归计算)吗?
For me, suspicious is the line f ln = f' ln >>= print >>= return (f' ln)
that does not pass the result of f' ln
to return.
我同意,这显然是错误的。也许你想要这个:
f ln = f' ln >>= \x -> print x >> return x
有多种其他方式可以表达同一件事。
Is it correct to say that a function of type IO a
always has to return
type a
?
不,有几个原因。第一:IO a
类型的值不是函数!第二:IO a
动作并不总是 returns;例如 exitWith ExitSuccess
没有。最后,也是最关键的:return
不是结束 IO
动作的唯一方法,因为还有许多其他基本动作。例如,getChar
是一个 IO
动作,不会调用 return
-- 它是由编译器作为原语实现的。* 一个动作类型 IO a
总是允许通过调用一些其他类型 IO a
的操作来完成自身,包括编译器原语,而不是 return
ing 类型 a
的值。
As we can see we can perform IO ()
operations in a function of type IO a
- but do we really have to have such a clumsy code if we print in such functions?
我不知道。我不知道你认为笨拙的是什么。如果你能把这个问题问得更详细一些objective,我很乐意回答。
What would be the most effective implementation?
我会写main = mapM foo [3, 2, 6, 8] >>= print
。如果你不允许我使用标准库中的 mapM
,我会先实现它,例如作为
mapM f [] = return []
mapM f (x:xs) = do
y <- f x
ys <- mapM f xs
return (y:ys)
Should we generally avoid the dual use (IO operations and recursive computations) in one function?
不,IO 和递归计算相得益彰;几乎所有 main
我写过的混合 IO
和递归。
*好吧,其实我也不知道getChar
是否调用了return
。它可能。但如果它确实如此,那是因为它调用了一些其他更原始的东西,它不以 return
.
结尾
...假设 a
是某种类型,例如[Int],我们想要迭代,例如获取所有元素,对它们进行操作并在操作后打印结果,如操作发生在以下代码中:
fa :: [Int] -> [Int]
fa [] = []
fa (n:rln) = (n + 1) : fa rln
...但是在函数类型中
fb :: [Int] -> IO [Int]
...这样
main :: IO ()
main =
do
fb [3, 2, 6, 8] >>= print
...将按顺序打印给定列表 ([4, 3, 7, 9]) 并再次打印结果。
分化和背景
我想了解类型的本质'IO a'。
这个问题不是关于如何迭代折叠和 fmap 等现成函数的问题。
这不是打印和return相同结果是否有意义的问题。
到目前为止的代码
到目前为止,我已经得到了这个“野兽”:
f :: [Int] -> IO [Int]
f ln = f' ln >>= print >>= return (f' ln)
where
f' :: [Int] -> IO [Int]
f' [] = return []
f' (n:rln) = f' rln >>= (\r -> return ((n + 1) : r))
...可以像这样在 main 中应用
main :: IO ()
main = f [3, 2, 6, 8] >>= (putStrLn . (\r -> "result=" ++ show r))
...打印:
[4,3,7,9]
result=[4,3,7,9]
对我来说,可疑的是行 f ln = f' ln >>= print >>= return (f' ln)
没有将 f' ln
的结果传递给 return。
问题
类型的本质是什么IO a
?
特别是:
IO a
类型的函数总是return
类型a
的说法正确吗?- 正如我们所见,我们可以在
IO a
类型的函数中执行IO ()
操作 - 但是如果我们在这样的函数中打印,我们真的需要这么笨拙的代码吗? - 最有效的实施方式是什么?
- 我们通常应该避免在一个函数中双重使用(IO 操作和递归计算)吗?
For me, suspicious is the line
f ln = f' ln >>= print >>= return (f' ln)
that does not pass the result off' ln
to return.
我同意,这显然是错误的。也许你想要这个:
f ln = f' ln >>= \x -> print x >> return x
有多种其他方式可以表达同一件事。
Is it correct to say that a function of type
IO a
always has toreturn
typea
?
不,有几个原因。第一:IO a
类型的值不是函数!第二:IO a
动作并不总是 returns;例如 exitWith ExitSuccess
没有。最后,也是最关键的:return
不是结束 IO
动作的唯一方法,因为还有许多其他基本动作。例如,getChar
是一个 IO
动作,不会调用 return
-- 它是由编译器作为原语实现的。* 一个动作类型 IO a
总是允许通过调用一些其他类型 IO a
的操作来完成自身,包括编译器原语,而不是 return
ing 类型 a
的值。
As we can see we can perform
IO ()
operations in a function of typeIO a
- but do we really have to have such a clumsy code if we print in such functions?
我不知道。我不知道你认为笨拙的是什么。如果你能把这个问题问得更详细一些objective,我很乐意回答。
What would be the most effective implementation?
我会写main = mapM foo [3, 2, 6, 8] >>= print
。如果你不允许我使用标准库中的 mapM
,我会先实现它,例如作为
mapM f [] = return []
mapM f (x:xs) = do
y <- f x
ys <- mapM f xs
return (y:ys)
Should we generally avoid the dual use (IO operations and recursive computations) in one function?
不,IO 和递归计算相得益彰;几乎所有 main
我写过的混合 IO
和递归。
*好吧,其实我也不知道getChar
是否调用了return
。它可能。但如果它确实如此,那是因为它调用了一些其他更原始的东西,它不以 return
.