You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 21:55:14