haskell - 值在 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
不评估。从我的直觉来看,以前很明显,但现在已经不明显了……但是对此有答案(尤其是来自 Tanner Swett)
解决方案
GHC 8.10.3 确实用 -Wall 抱怨了这一点(在我在你的代码中更改initConfig
为之后):readConfig
一个 do-notation 语句丢弃了 'IO ()' 类型的结果<br /> 通过说 '_ <- print <$> readConfig c'</p> 抑制此警告
你有readConfig c
type IO Int
。然后你 fmap print
,给出一个类型为IO (IO ())
. 由于结果没有绑定到 do 块中的变量,因此它被丢弃了。
在 fmap 的类型中,Functor f => (a -> b) -> f a -> f b
我们有f
being IO
、a
beingInt
和b
being IO ()
。所以它与 type 一起使用(Int -> IO ()) -> IO Int -> IO (IO ())
。
这会起作用:
printAction <- print <$> readConfig c
printAction
但你真正想要的是绑定:
print =<< readConfig c
推荐阅读
- redux - Redux 等待异步 thunk 继续进行
- azure-devops - 如何自动解压通过 devops 部署的 zip?
- javascript - 如何将背景颜色添加到 Google 图表中的特定行
- c# - C# IList 更新问题
- python - 在 keras 中调用 to_categorical 时出现 MemoryError
- sql - 引用的字符串在 SQL 中未正确终止
- html - 边缘填充导致文本在环绕和非环绕之间交替
- python - 在 Python 数据框中按年度日期填补空白的最佳方法
- c# - 更新 Cookie 以删除元素 C#
- c++ - MFC C++ CListCtrl - 删除所有项目不会回收内存