haskell - 混合 MonadIO、MonadState 和缩放时出现 "Could not deduce"错误

标签 haskell haskell-lens

我在进行简单的蒙特卡洛模拟时遇到了这个问题。我使用 MonadIOMonadStateMonadRandom 来简化程序状态的维护。我遇到了 Count not deduce 错误,但是当我删除程序的顶级 monad 的类型时,它突然编译得很好。

我是不是对这种类型做错了什么?我需要指定更严格的类型吗?您能解释一下为什么添加类型信息会导致类型计算更加模糊而不是更加模糊吗?

更新

我尝试在 ghci 中使用 :t 来获取类型,我得到了 (Field1 s s Int Int, Zoom m n Int s, Functor (Zoomed m ()))。我在我原来的程序中做了同样的事情,得到了 (Zoom m1 m (Map Int Int) ProgramState, Functor (Zoomed m1 ()), MonadRandom m1, MonadIO m)

我很高兴在这里有一些东西,但由于放入类型的主要目的是使代码更具可读性并使错误消息更好,我想了解如何生成和读取这些类型。

我还想更好地理解添加类型约束如何导致类型计算变得不明确。

结束更新

我简化了代码:

{-# LANGUAGE FlexibleContexts #-}
import Control.Monad.State.Strict
import Control.Lens

updateCount :: (MonadState Int a) => a ()
updateCount = modify (+ 1)

run :: MonadState (Int, Int) a => a ()
run = zoom _1 updateCount

main = execStateT run (0, 0) >>= print

如果我删除 run:: 行,一切正常,但如果我尝试按原样编译,我会收到以下错误:

[1 of 1] Compiling Main             ( bug-report.hs, bug-report.o )

bug-report.hs:9:7: error:
    • Could not deduce (Zoom m0 a Int (Int, Int))
        arising from a use of ‘zoom’
      from the context: MonadState (Int, Int) a
        bound by the type signature for:
                   run :: MonadState (Int, Int) a => a ()
        at bug-report.hs:8:1-38
      The type variable ‘m0’ is ambiguous
      Relevant bindings include run :: a () (bound at bug-report.hs:9:1)
      These potential instances exist:
        instance Monad z => Zoom (StateT s z) (StateT t z) s t
          -- Defined in ‘Control.Lens.Zoom’
        ...plus 12 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the expression: zoom _1 updateCount
      In an equation for ‘run’: run = zoom _1 updateCount

bug-report.hs:9:12: error:
    • Could not deduce (Functor (Zoomed m0 ()))
        arising from a use of ‘_1’
      from the context: MonadState (Int, Int) a
        bound by the type signature for:
                   run :: MonadState (Int, Int) a => a ()
        at bug-report.hs:8:1-38
      The type variable ‘m0’ is ambiguous
      These potential instances exist:
        instance Functor Identity -- Defined in ‘Data.Functor.Identity’
        instance Functor IO -- Defined in ‘GHC.Base’
        instance [safe] Functor m => Functor (StateT s m)
          -- Defined in ‘Control.Monad.Trans.State.Strict’
        ...plus four others
        ...plus 41 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘zoom’, namely ‘_1’
      In the expression: zoom _1 updateCount
      In an equation for ‘run’: run = zoom _1 updateCount

bug-report.hs:9:15: error:
    • Could not deduce (MonadState Int m0)
        arising from a use of ‘updateCount’
      from the context: MonadState (Int, Int) a
        bound by the type signature for:
                   run :: MonadState (Int, Int) a => a ()
        at bug-report.hs:8:1-38
      The type variable ‘m0’ is ambiguous
      These potential instances exist:
        instance [safe] Monad m => MonadState s (StateT s m)
          -- Defined in ‘Control.Monad.State.Class’
        ...plus 13 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the second argument of ‘zoom’, namely ‘updateCount’
      In the expression: zoom _1 updateCount
      In an equation for ‘run’: run = zoom _1 updateCount

最佳答案

Zoom不允许你在 MonadState 上多态工作一般因为MonadState单独没有提供一种方法来换出状态的类型。

也就是说,如果你想使用Zoom ,您可能应该使用混凝土 StateT , 如果你不需要 StateT 的多态性具体而言,只能在底层 monad 上使用多态性(即 m 中的 StateT s m)。或者,您可以跳过 zoom并且仍然使用透镜来关注纯函数的状态部分,使用像 modifying 这样的组合器—在这里,modifying _1 (+ 1) .

当您删除 run 的类型签名时,推断类型(使用 NoMonomorphismRestriction )是这样的:

run ::
  ( Zoom m n Int s
  , Field1 s s Int Int
  , Functor (Zoomed m ())
  )
  => n ()

即:

  • 一些外部 monad 中的 Action n其状态是s (这里,(Int, Int))

  • 在一些内部 monad 中包装一个 Action m其状态是Int

  • 您可以在哪里查看和更新​​ Ints 的第一个索引处

  • Zoomed m ()Functor , 其中类型族申请 Zoomed (StateT s u) ()评估为 Focusing u () ;这是必需的,因为 Functor镜头类型的限制,Functor f => (a -> f b) -> (s -> f t)

Functor约束在这里是必需的,因为直到类型族 Zoomed 编译器才能推断出它。应用于混凝土 m .请注意,您不需要 MonadState不过,约束是因为 Zoom 隐含了它.

您可以通过几种不同的方式稍微简化这一过程,具体取决于您的特定用例。例如,使用具体的外部状态:

run ::
  ( Zoom m n Int (Int, Int)
  , Functor (Zoomed m ())
  )
  => n ()

或者将责任传递给调用者并采取 Lens :

runOn
  :: (Zoom m n Int s, Functor (Zoomed m ()))
  => LensLike' (Zoomed m ()) s Int
  -> n ()
runOn lens = zoom lens updateCount
print =<< execStateT (runOn _1) (0 :: Int, 0 :: Int)

关于haskell - 混合 MonadIO、MonadState 和缩放时出现 "Could not deduce"错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65115309/

相关文章:

haskell - XMonad 中只有内部间距

haskell - 无限循环 Haskell

haskell - 通过 ReaderT 获取带有镜头的元组子集

haskell - 当我的 getter 和 setter 返回 `Either` 时,我可以构建类似镜头的东西吗?

haskell - 使用 DuplicateRecordFields 创建镜头

haskell - 无法推断因使用 ‘>’ 而产生的 (Ord a0)

windows - Windows 安装程序上的 Haskell

haskell - 为什么 “failing”(来自镜头)会产生无效遍历?

json - 具有错误处理功能的 Aeson 和 Lenses

windows - 无法加载 OpenGL 进程,只能从 Haskell 加载