我不明白為什么會發生這種情況:
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不評估。根據我的直覺,以前很明顯,但現在不是了……但是對此有答案(尤其是來自 Tanner Swett)
uj5u.com熱心網友回復:
GHC 8.10.3 確實使用 -Wall 對此進行了抱怨(在我更改initConfig為readConfig您的代碼之后):
do-notation 陳述句丟棄了型別為 'IO ()' 的結果
通過說 '_ <- print <$> readConfig c' 來抑制此警告
你有readConfig c型別IO Int。然后你 fmap print,給一些帶有IO (IO ()). 由于結果未系結到 do 塊中的變數,因此將其丟棄。
在 fmap 的型別中,Functor f => (a -> b) -> f a -> f b我們有fbeing IO、abeingInt和bbeing IO ()。所以它與型別一起使用(Int -> IO ()) -> IO Int -> IO (IO ())。
這會起作用:
printAction <- print <$> readConfig c
printAction
但你真正想要的是一個系結:
print =<< readConfig c
轉載請註明出處,本文鏈接:https://www.uj5u.com/gongcheng/316831.html
