How do you include Effect in the render function?

I think understand the problem with the following code, but I don’t know how to fix it. In the render function I’m trying to use an Effect String as an argument to HH.text which, of course, doesn’t work because the types don’t match. So I tried using H.liftEffect, but get a message that there isn’t a bind instance.

:type window >>= navigator >>= userAgent 
Effect String

render :: forall a m. Unit -> H.ComponentHTML a () m
render _ = do
    ua <- H.liftEffect $ window >>= navigator >>= userAgent
    HH.div_ [ HH.text $ ua]

  No type class instance was found for
    Control.Bind.Bind (HTML (ComponentSlot HTML () m3 a4))
  while applying a function bind
    of type Bind t0 => t0 t1 -> (t1 -> t0 t2) -> t0 t2
    to argument (apply liftEffect) ((bind ((...) navigator)) userAgent)
  while inferring the type of bind ((apply liftEffect) ((bind (...)) userAgent))
  in value declaration render

I tried writing an instance, but orphan instances aren’t allowed and I got lost in the newtype wrapper stuff. I have a feeling I’m making this much harder than it really is What’s idiomatic way to do this?

Im running purs 0.13.6 and Halogen v5.0.0-rc.9

You can’t perform an effect during rendering, so you’ll need to perform the effect in your eval function and store the result in state.

For example, here you’d add an initializer which retrieved the user agent, store that in state, and then use the state in your render function.

Thanks. That worked easy enough…

What the ‘m’ for in the type signature for render? I assumed it was for a monad type.

render :: forall a m. Unit -> H.ComponentHTML a () m

Off the top of my head I can’t remember exactly why the monad type is required in ComponentHTML, but I believe it’s there because once you run the component in a slot you only have ComponentHTML remaining, but you still need to know what the component’s monad type is.

1 Like

All components need to unify with the same m. When you embed a child component, it has to be tracked in ComponentHTML so that it can unify with the m in the component you are creating,

1 Like