使用'print'不会产生(Show(IO()))的实例

gra*_*upa 3 haskell

只是为了学习我在我的控制台WinGHCi上做了这个:

let ls = [putChar 'x',putChar 'y']
Run Code Online (Sandbox Code Playgroud)

那么如果:

head ls
Run Code Online (Sandbox Code Playgroud)

输出是显而易见的 x (在我看来为什么不明显的意义上)

如果我这样做:

tail ls
Run Code Online (Sandbox Code Playgroud)

我收到此错误:

使用'print'不会产生(Show(IO()))的实例

在交互式GHCi命令的stmt中:打印它

为什么?不应该输出y[putChar 'y']

Lee*_*Lee 13

此处解释此行为.

head ls有类型,IO ()所以GCHi执行动作,不打印结果().

相比之下,tail ls有类型[IO ()].由于这不是一个IO动作,GCHi尝试使用print哪个类型显示它:

print :: Show a => a -> IO ()
Run Code Online (Sandbox Code Playgroud)

但是因为没有Show实例[IO ()]可以获得错误.如果要评估可以使用的操作sequence_:

sequence_ (tail ls)
Run Code Online (Sandbox Code Playgroud)


lef*_*out 6

那么如果:head ls 输出是显而易见的x

好吧,其实不是很明显!实际上,head ls并不是与角色直接相关的东西'x'.首先,它只是一个IO动作,GHCi假设这个动作做了你想要发生的事情:它有一个特殊的处理,对于一个IO动作,它试图不显示动作,但执行它.嗯,很好,你没有考虑列表[launchMissiles, putStrLn "oops"]......

现在,执行该操作确实会导致将字符'x'打印到控制台,这恰好也是您的视口,因此您将其视为仅仅是值的值putChar 'x'.但事实并非如此!

OTOH,tail ls来自外面只是一个列表,所以ghci不假设你想要任何执行.它确实尝试显示列表,但您无法显示 IO操作或其中包含IO操作的任何内容; 这就是错误信息所说的内容.


bhe*_*ilr 5

当你有

> let ls = [putChar 'x', putChar 'y']
Run Code Online (Sandbox Code Playgroud)

您没有执行存储在该列表中的操作,您只是构建这些操作,如果这是有意义的.你可以有类似的东西

printHelp :: IO ()
printHelp = putStrLn "You need to pass XYZ options to this program"
Run Code Online (Sandbox Code Playgroud)

在文件中定义.这不会立即打印出消息,而是构造一个动作,一旦执行,就会将该消息打印到控制台.执行发生在两个地方之一:在main函数和GHCi中.

看起来你正在使用GHCi来执行代码,这对于探索不同的函数来说非常棒,但与在文件中执行代码有点不同.每当您IO Something在GHCi中自行评估一个动作时,它就会运行该IO动作.无论何时评估GHCi中的任何其他值,它都会插入print该行的前面.所以,当你这样做

> head ls
Run Code Online (Sandbox Code Playgroud)

这有类型IO (),因此putChar 'x'执行操作,导致x打印到控制台.当你这样做

> tail ls
Run Code Online (Sandbox Code Playgroud)

这有类型[IO ()],所以GHCi试图把print它放在它前面,使它等同于

> print (tail ls)
Run Code Online (Sandbox Code Playgroud)

print函数有类型

print :: (Show a) => a -> IO ()
Run Code Online (Sandbox Code Playgroud)

我们已经将列表传递到print此处,并且存在Showfor列表的实例,但仅当列表的元素具有实例时才有Show.因此编译器会尝试查看是否IO ()有实例Show.不幸的是,它没有,因为它IO是一个非常复杂的类型,代表几乎任何事情都可能发生.因此编译器会显示一个IO ()没有实例的错误Show.

如果你想按顺序运行列表中的每个动作,那么就有一个功能:( Control.Monad.sequence或者Control.Monad.sequence_如果你不关心结果).这个功能实际上适用于所有Monads,而不仅仅是IO:

> sequence_ (tail ls)
y> sequence_ ls
xy>
Run Code Online (Sandbox Code Playgroud)