根据定义对无限的 IO 操作列表进行排序是否会导致永无止境的操作?或者有什么办法可以摆脱吗?

问题描述 投票:0回答:1

这实际上是我想通过我之前的问题来理解的,但我用词不当,想当然地认为解决方案必须以

sequence
repeat
为基础,所以我得到了一个有趣的答案,这绝对是对于解决手头的问题很有用,但我实际上也没有解决我的好奇心,所以我按照标题重新表述了这个问题。

正如您从链接的问题中看到的,我最初写的是

main :: IO ()
main = do
  x <- takeWhile (/= 'q') <$> sequence (repeat getChar)
  print "you pressed q"

认为

x
将是有限长度
[Char]

但我知道我的印象是我并没有“只是”使用了上面错误的工具(

takeWhile
,一个纯函数),但实际上根本没有(正统)工具可以从中摆脱出来
IO [Char] 
sequence (repeat getChar)

我说得对吗?

如果没有,那么你如何摆脱困境?

注意,我现在不会问与之前相同的问题。我正在寻找一种确实利用

sequence (repeat getChar)
并且仍然设法实现
print "you pressed q"
操作的解决方案,或者解释为什么这样的解决方案不存在。

haskell functional-programming language-lawyer proof io-monad
1个回答
0
投票

如果您

sequence
有无限的
IO
操作列表,则无法通过“纯”程序逻辑来退出。所以,你是对的,没有“正统”工具可以摆脱
sequence (repeat getChar)

摆脱困境的唯一方法是调用

IO
效果来执行“不纯”的摆脱困境,例如通过引发异常、终止线程、退出程序或类似的方式。在这些情况下,您无法轻松返回值,因此这对于您的用例来说不是很有用。或者,您可以“欺骗”并使用不安全的惰性 I/O,而不是退出,这允许您执行无限操作列表的初始前缀并检查返回列表的初始前缀。您可以无限期地继续处理列表,也可以在处理有限数量的元素后“放弃”列表。

不过,总的来说,这两种方法都不是好的做法,至少对于你的问题来说是这样。

如果你想编写一个正确的单子操作来读取字符直到第一个

'q'
,那么使用基本 Haskell 代码的正确方法是这样的:

getToQ :: IO String
getToQ = do
  c <- getChar
  if c == 'q' then pure [] else do
    cs <- getToQ
    pure (c:cs)

无法使用

sequence
来实现此逻辑的技术原因是,这是一个基本的一元算法,但
sequence
“仅”是一个应用组合器。应用组合器不能使用应用操作的结果来影响计算的“结构”。当您
sequence
IO
操作的无限列表时,您已承诺执行无限循环,并且操作的结果不能将其更改为有限循环,除非作为副作用(异常等)。特别是
sequence
无法实现
getToQ
的部分,我们检查返回值
c
并决定剩余的计算是
pure []
还是递归调用
getToQ
来执行更多操作
getChar
s。您可以从以下
sequence
的(简化)定义中看到这一点:

sequence [] = pure []
sequence (x:xs) = do
  a <- x
  as <- sequence xs
  pure (a:as)

看看从

a
操作返回的
x
值如何不能用于影响下一行中的
sequence xs
操作是否执行?这就是
sequence
在结构上与
getToQ
的不同之处。

现在,有一些包,如

extra
monad-loops
提供了单子组合器,可用于简洁地编写
getToQ
的等效项。例如,从
monad-loops
开始,
unfoldWhileM
将完全按照您的要求进行操作:

unfoldWhileM (/= 'q') getChar

这些组合器并没有什么神奇之处。该组合器的简化实现是:

unfoldWhileM :: Monad m => (a -> Bool) -> m a -> m [a]
unfoldWhileM p x = do
  a <- x
  if p a then do
      as <- unfoldWhileM p x
      pure (a:as)
    else pure []

看看这个组合器与

sequence
相比,如何成为一个非应用性的单子组合器。它使用操作
a
的返回值
x
来确定其余计算的结构: (i) 递归执行更多
x
操作;或 (ii) 结束计算。

© www.soinside.com 2019 - 2024. All rights reserved.