Search code examples
purescripthalogen

How do I combine effectful event handlers and custom EventUpdates in purescript-halogen?


In my custom Halogen/Purescript project I follow the pattern from the AJAX Example where I split my actions up into pure Inputs and effectful Requests.

I want to change my event handler to use the preventDefault behavior, but don't understand what consequences for the type of the UI function this entails.

I made the same changes to the AJAX Example by changing the event handler the following way:

Before:

H.button [ A.classes [B.btn, B.btnPrimary]
         , A.disabled busy
         , A.onclick (\_ -> pure (handler code))
         ] [ H.text "Compile" ]

After:

H.a [ A.classes [B.btn, B.btnPrimary]
    , A.href "#compile"
    , A.disabled busy
    , A.onclick (\_ -> E.preventDefault $> pure (handler code))
    ] [ H.text "Compile" ]

(Full diff available here)

I end up with this type error:

Cannot unify type
    Example.Ajax.Input
    with type
        Halogen.HTML.Events.Monad.Event Halogen.HalogenEffects<(http ::
        Example.Ajax.HTTP | u32519)> Example.Ajax.Input

At this point, I'm a bit lost whether I would need to adjust the type signature of the UI function or I apply the preventDefault modifier the wrong way.


Solution

  • The type of $> looks like:

    ($>) :: forall a. EventHandler a -> b -> EventHandler b
    

    The type of pure looks like:

    pure :: forall a. a -> EventHandler a
    

    So the problem is by using both together, you're making a type which looks like this:

    EventHandler a -> EventHandler b -> EventHandler (EventHandler b)
    

    But you don't want that, you just want an EventHandler b, where b is the E.Event type of handler code.

    The best solution is to just not use pure:

    E.preventDefault $> handler code
    

    If sometime you do have two EventHandler values you want to use together like this, the function to use is *> instead of $>.