考虑以下代码(和错误):

import Control.Lens
import Control.Monad.STM
import Control.Monad.IO.Class
import Control.Monad.State.Lazy
import Control.Concurrent.STM.TChan

data Broadcast = Broadcast Int

data ImmutableState = ImmutableState
    { _broadcastChan :: TChan Broadcast
    , _encryption    :: Int
    }

makeLenses ''ImmutableState

helper :: MonadIO m => StateT ImmutableState m a
helper = do
    broadcastChan <~ (liftIO . atomically $ dupTChan $ use broadcastChan)
    {- ^
        Test.hs:
            Couldn't match expected type `Broadcast'
                        with actual type `TChan Broadcast'
            Expected type: StateT ImmutableState m (TChan Broadcast)
              Actual type: StateT ImmutableState m (TChan (TChan Broadcast))
            In the second argument of `(<~)', namely
              `(liftIO . atomically $ dupTChan $ use broadcastChan)'
            In a stmt of a 'do' block:
              broadcastChan
              <~ (liftIO . atomically $ dupTChan $ use broadcastChan)
    -}

forkImmState :: MonadIO m => ImmutableState -> m ImmutableState
forkImmState s = evalStateT helper s

有人能解释一下 (TChan (TChan Broadcast)) 是怎么来的吗?

最佳答案

dupTChan 需要一个类似 TChan a 的参数,并且正在应用类似 MonadState ImmutableState m => m (TChan Broadcast) 的东西。如果你直接尝试,你会得到一个稍微不同的类型错误

*Main> :t dupTChan $ use broadcastChan

<interactive>:1:12:
    No instance for (MonadState ImmutableState TChan)
      arising from a use of `use'
    Possible fix:
      add an instance declaration for (MonadState ImmutableState TChan)
    In the second argument of `($)', namely `use broadcastChan'
    In the expression: dupTChan $ use broadcastChan

GHC 尝试通过使用 TChan am (TChan Broadcast) 来统一 a ~ TChan Broadcastm ~ TChan ,但它失败了,因为 TChan 不是 MoandState 的实例。您已经可以看到 TChan (TChan Broadcast) 错误是如何形成的,但它无法统一,所以它停止了。

只有当我们声称我们知道结果的类型时,GHC 才会告诉我们它在幕后尝试了什么
*Main> :t (dupTChan $ use broadcastChan) :: STM (TChan Broadcast)

<interactive>:1:2:
    Couldn't match type `TChan Broadcast' with `Broadcast'
    Expected type: STM (TChan Broadcast)
      Actual type: STM (TChan (TChan Broadcast))
    In the expression:
        (dupTChan $ use broadcastChan) :: STM (TChan Broadcast)

关于Haskell:在使用镜头修改状态时重复 TChan 包装,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/17099881/

10-13 07:29