Haskell 为 'show' 显式声明参数时出现 IO-Monad 错误

Haskell IO-Monad error upon explicitly stating parameter for 'show'

虽然我觉得自己对 Haskel IO 和 Monads 有很好的理解,但我很难理解以下错误消息。

考虑 Haskell

中的以下简单函数
testf :: Show a => a -> String
testf x = show x

我尝试实现一个使用 IO Monad 打印到控制台的变体

printtoscreen :: Show a => a -> IO()
printtoscreen x = putStrLn . show x

但是,这会产生以下错误:

Couldn't match type ‘[Char]’ with ‘a0 -> String’ Expected type: a0 -> String Actual type: String

正确的版本应该省略明确说明 x 参数

printtoscreen :: Show a => a -> IO()
printtoscreen = putStrLn . show

我明白为什么最后一个代码片段有效,但我无法理解第二个代码片段的错误消息,考虑到它也会 return 一个字符串到 putStrLn

那么为什么要在 IO() 变体中省略 x 参数?

.,函数组合运算符,需要一个函数。 show x 然而不是函数;它是一个评估值([Char] 类型)在它被赋予 ..

您必须改用函数应用程序运算符:

printtoscreen x = putStrLn $ show x

So why should the x parameter be omitted in the IO () variant?

这与IO ()本身无关。您在这里使用函数组合。实际上,(.) :: (b -> c) -> (a -> b) -> a -> c 函数定义为:

(.) :: (b -> c) -> (a -> b) -> a -> c
(.) f g x = f (g x)

因此用于将两个函数 fg 组合在一个新函数中,该函数首先将 g 应用于参数,然后将 f 应用于结果g x.

如果你写:

printtoscreen x = putStrLn . show x

然后 (.) 函数会将其解析为:

printtoscreen x = \y -> putStrLn (show x y)

或因此更容易阅读:

printtoscreen x y = putStrLn (show x y)

这意味着 show 应该有类型 Show a => a -> b -> String,但它有类型 show :: Show a => a -> String,因此错误。