我不明白为什么会发生这种情况:
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"
Run Code Online (Sandbox Code Playgroud)
结果就是:
"Start"
2
"Done"
Run Code Online (Sandbox Code Playgroud)
为什么是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 ()
Run Code Online (Sandbox Code Playgroud)
现在我只想知道为什么let t不评价。从我的直觉来看,这在以前是显而易见的,但现在不再了......但是这个问题有答案(尤其是来自 Tanner Swett)
GHC 8.10.3 确实对 -Wall 抱怨这一点(在我在代码中更改initConfig为之后):readConfig
\n\ndo-notation 语句丢弃了 \xe2\x80\x98IO ()\xe2\x80\x99 类型的结果 \
\n
n通过说 \xe2\x80\x98_ <- print <$> readConfig c\xe2\x80\x99 来抑制此警告
你有readConfig c类型IO Int。然后你 fmap print,给出类型为 的东西IO (IO ())。由于结果未绑定到 do 块中的变量,因此它被丢弃。
在 fmap 的类型中,Functor f => (a -> b) -> f a -> f b我们有fbeing IO、abeingInt和bbeing IO ()。所以它与 type 一起使用(Int -> IO ()) -> IO Int -> IO (IO ())。
这会起作用:
\nprintAction <- print <$> readConfig c\nprintAction\nRun Code Online (Sandbox Code Playgroud)\n但你真正想要的是一个绑定:
\nprint =<< readConfig c\nRun Code Online (Sandbox Code Playgroud)\n