Haskell:STM writeTVar嵌套Monad错误排查求助
Haskell STM嵌套Monad错误修复
原代码
module MyLib (write) where import Control.Monad.STM import Control.Concurrent.STM.TVar write :: STM (TVar Störm) -> Störm -> IO () write state' new = atomically $ write' state' where write' :: STM (TVar Störm) -> STM () write' state' = write'' <$> state' write'' :: TVar Störm -> STM () write'' state' = writeTVar state' new
编译错误
src/MyLib.hs:39:25: error: • Couldn't match type ‘STM ()’ with ‘()’ Expected: TVar Störm -> () Actual: TVar Störm -> STM () • In the first argument of ‘(<$>)’, namely ‘write''’ In the expression: write'' <$> state' In an equation for ‘write'’: write' state' = write'' <$> state' | 39 | write' state' = write'' <$> state'
问题原因
你用<$>(fmap)把write''映射到state'(类型为STM (TVar Störm))上,得到的结果是STM (STM ())——因为write''接受TVar Störm返回STM (),fmap会把这个函数的结果包裹进外层的STM里,形成嵌套的Monad。但write'的返回类型要求是STM (),类型不匹配导致报错。
修复方案
需要把嵌套的STM (STM ())合并为单层STM (),有三种常用方式:
方式1:使用do表达式(最直观)
module MyLib (write) where import Control.Monad.STM import Control.Concurrent.STM.TVar write :: STM (TVar Störm) -> Störm -> IO () write state' new = atomically $ write' state' where write' :: STM (TVar Störm) -> STM () write' state' = do tvar <- state' -- 从STM动作中取出TVar write'' tvar -- 执行写TVar的STM动作 write'' :: TVar Störm -> STM () write'' state' = writeTVar state' new
方式2:使用Monad绑定(>>=)
直接用绑定操作把state'的结果传给write'',自动合并嵌套的STM:
write' state' = state' >>= write''
方式3:使用join合并嵌套Monad
join可以把m (m a)转为m a,结合fmap使用需要额外导入Control.Monad:
import Control.Monad (join) import Control.Monad.STM import Control.Concurrent.STM.TVar write :: STM (TVar Störm) -> Störm -> IO () write state' new = atomically $ write' state' where write' :: STM (TVar Störm) -> STM () write' state' = join $ write'' <$> state' write'' :: TVar Störm -> STM () write'' state' = writeTVar state' new
这三种方式都能解决类型不匹配的问题,最终实现从STM动作中获取TVar并执行写操作的逻辑。
内容的提问来源于stack exchange,提问作者Erdel von Mises
相关产品推荐
相关产品推荐

