值在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,也没有人抱怨这个…

(我试着diff ghc godbolt版本,但结果保持不变)

编辑:好吧,我发现了一个等价的描述问题,thx @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不计算。从我的直觉来看,这一点以前很明显,但现在不是了……但这是有答案的(尤其是来自坦纳·斯威特)

GHC 8.10.3确实抱怨这个与-Wall(在我改变initConfigreadConfig在你的代码):

do-notation语句丢弃了类型' IO() '的结果
通过声明' _ <- print <$>readConfig c '

您的readConfig c类型为IO Int。然后映射print,得到IO (IO ())类型的东西。由于结果没有绑定到do块中的变量,因此会被丢弃。

fmap的类型Functor f => (a -> b) -> f a -> f b我们fIO,aInt,bIO ()。因此,它与类型(Int -> IO ()) -> IO Int -> IO (IO ())一起使用。

可以:

printAction <- print <$> readConfig c
printAction

但是你真正想要的是绑定:

print =<< readConfig c

相关内容

  • 没有找到相关文章

最新更新