理解 Purescript Eff Monad 和 do 块

Understanding Purescript Eff Monad and do blocks

我想了解为什么以下内容在 Purescript 中不起作用。我觉得 Haskell 社区也可以回答这个问题,因此我交叉列出了它。

总的要点是:

如果我有一个do块,我可以不扔一个一次性值吗?在这种情况下,我试图在一系列单子计算的中间记录一些东西(类似于 Haskell 的 print)。

main = do
    a <- someAction1
    b <- someAction2
    _ <- log "here is a statement I want printed"
    someAction3 a b

具体来说,我有一个函数采用以下内容(来自 Halogen 示例模板项目)

data Query a = ToggleState a

eval :: Query ~> H.ComponentDSL State Query g
eval (Toggle next) = do
    H.modify (\state -> state { isOn = not state.isOn })
    _ <- log "updating the state!"
    pure next

在我看来,这应该像 Haskell

中那样工作
barf :: IO Int
barf = do
  _ <- print "Here I am!"
  return 5

main :: IO ()
main = do
  a <- barf
  _ <- print $ "the value is: " ++ (show a)
  print "done"

具体来说,我得到的错误是 monad 的类型不匹配

Could not match type Eff with type Free while trying to match type Eff ( "console" :: CONSOLE | t6 ) with type Free (HalogenFP t0 { "isOn" :: t1 | t2 } t3 t4) ... etc...

我知道 purescript 让我声明 "things I'm touching in the monad"(即 forall e. Eff ( a :: SOMEVAR, b :: SOMEOTHERVAR | eff ) Unit,但我不确定在这种情况下该怎么做...

如果您使用的是 0.12.0 版的卤素,您应该能够像这样使用 https://pursuit.purescript.org/packages/purescript-aff-free/3.0.0/docs/Control.Monad.Aff.Free#v:fromEff 中的 fromEff

data Query a = ToggleState a

eval :: Query ~> H.ComponentDSL State Query g
eval (Toggle next) = do
    H.modify (\state -> state { isOn = not state.isOn })
    _ <- H.fromEff (log "updating the state!")
    pure next

这在即将推出的卤素 (>= 0.13) 版本中会变得更好,其中 liftEff 应该足够了。

您不能立即使用 log 的原因是 H.ComponentDSL 不是 Eff 的类型同义词,而是 Free 和所以你不能简单地混合 EffComponentDSL 动作。