【问题标题】:Haskell IO-Monad error upon explicitly stating parameter for 'show'Haskell IO-Monad 在明确声明“show”参数时出错
【发布时间】:2020-01-08 13:17:28
【问题描述】:

虽然我觉得对 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

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

无法将类型“[Char]”与“a0 -> String”匹配 预期类型:a0 -> 字符串 实际类型:字符串

正确的版本应该省略显式声明x 参数

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

我理解为什么最后一个代码 sn-p 有效,但我无法理解第二个代码 sn-p 的错误消息,因为它也会返回一个字符串到 putStrLn

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

【问题讨论】:

  • putStrLn . show x 表示\y -> putStrLn (show x y),所以你用printtoscreen x y = putStrLn (show x y) 实现了一个函数。因此这意味着show 应该具有Show a => a -> b -> String 类型,但类型当然是Show a => a -> String
  • 说得通,putStrLn (show x) 确实有效!非常感谢,原来这个错误超出了 IO Monads 的范围
  • 这里的问题是putStrLn . show x 被解析为putStrLn . (show x) 而不是(putStrLn . show) x。这是因为函数应用程序 show x 的优先级高于任何二元运算符:这就是 1 + f x 在没有额外括号的情况下正确的原因。
  • 可能不是严格意义上的重复,但阅读答案here 应该可以帮助您更好地了解正在发生的事情。

标签: haskell io-monad


【解决方案1】:

.,函数组合运算符,需要一个函数。 show x 但是不是函数;在将其提供给 . 时,它是一个评估值([Char] 类型)。

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

printtoscreen x = putStrLn $ show x

【讨论】:

    【解决方案2】:

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

    这与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,因此会出现错误。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2023-03-29
      • 1970-01-01
      • 1970-01-01
      • 2014-05-25
      • 1970-01-01
      • 2013-08-15
      相关资源
      最近更新 更多