Haskell 中的值被丢弃

Value is discarded in Haskell

我不明白为什么会这样:

module Main where

import Control.Monad.Reader

data Config = Config Int

getA :: (Monad m) => ReaderT Config m Int
getA = do
  Config a <- ask
  return a

readConfig :: Config -> IO Int
readConfig = runReaderT getA

main :: IO ()
main = do
  print "Start"
  let a = Config 2
  b <- readConfig a -- Will be printed
  print b
  let c = Config 4
  print <$> readConfig c -- Silence, nobody complains..
  print "Done"

结果是:

"Start"
2
"Done"

为什么 print <$> readConfig a 是空的?即使 -Wall 也没有人抱怨这个...

(我在 godbolt 中尝试了 diff ghc 版本,但结果保持不变)

编辑: 好的,我找到了问题的等效描述,感谢@chi和@David:

module Main where
test :: IO ()
test = do 
    print "test"
    return ()

main :: IO ()
main = do
  let t = test -- equivalent to print <$> readConfig c, is IO (IO ())
  test -- equivalent to print b is IO ()

现在,我只想知道为什么 let t 不评估。根据我的直觉,以前很明显,但现在不明显了......但是有答案(esp. from Tanner Swett)

GHC 8.10.3 确实用 -Wall 抱怨这个(在我将你的代码中的 initConfig 更改为 readConfig 之后):

A do-notation statement discarded a result of type ‘IO ()’
Suppress this warning by saying ‘_ <- print <$> readConfig c’

您有 readConfig c 类型 IO Int。然后你 fmap print,给出类型为 IO (IO ()) 的东西。由于结果未绑定到 do 块中的变量,因此将其丢弃。

在 fmap 的类型 Functor f => (a -> b) -> f a -> f b 中,我们有 fIOaIntbIO ().所以它与 (Int -> IO ()) -> IO Int -> IO (IO ()).

类型一起使用

这可行:

printAction <- print <$> readConfig c
printAction

但你真正想要的是绑定:

print =<< readConfig c