I’m trying to see if I can use Halogen Hooks to draw on a canvas but I’m having trouble getting the types to line up in the useTickEffect
block.
I’ve primarily been looking at Example.Hooks.UsePreviousValue (v0.4.2) to write the hook itself and the myComponent
code block in Introducing Halogen Hooks to call the hook.
Here’s my code so far:
module Main where
import Prelude
import Data.Newtype (class Newtype)
import Data.Traversable (sequence)
import Effect (Effect)
import Effect.Aff.Class (class MonadAff)
import Effect.Class (liftEffect)
import Graphics.Canvas (Context2D, fillRect, getCanvasElementById, getContext2D, setFillStyle)
import Halogen as H
import Halogen.Aff as HA
import Halogen.HTML as HH
import Halogen.HTML.Properties as HP
import Halogen.Hooks (Hook, UseEffect)
import Halogen.Hooks as Hooks
import Halogen.VDom.Driver (runUI)
main :: Effect Unit
main =
HA.runHalogenAff do
body <- HA.awaitBody
runUI canvasComponent unit body
canvasComponent ::
forall query input output m.
MonadAff m =>
H.Component HH.HTML query input output m
canvasComponent =
Hooks.component \_ _ -> Hooks.do
drawOnCanvas
Hooks.pure $ HH.canvas [ HP.id_ "canvas", HP.width 300, HP.height 300 ]
newtype DrawOnCanvas hooks
= DrawOnCanvas (UseEffect hooks)
derive instance newtypeDrawOnCanvas :: Newtype (DrawOnCanvas hooks) _
drawOnCanvas :: forall m. MonadAff m => Hook m DrawOnCanvas Unit
drawOnCanvas =
Hooks.wrap Hooks.do
Hooks.captures {} Hooks.useTickEffect do
-- Error on next line: Could not match type Maybe with type HookM t0
mcanvas <- liftEffect $ getCanvasElementById "canvas"
mcontext <- liftEffect $ sequence $ getContext2D <$> mcanvas
drawRect <$> mcontext
pure unit
Hooks.pure unit
where
drawRect context = do
liftEffect $ setFillStyle context "red"
liftEffect
$ fillRect context { x: 100.0, y: 50.0, width: 200.0, height: 25.0 }
The full error message is:
[1/1 TypesDoNotUnify] src/Main.purs:42:7
42 mcanvas <- liftEffect $ getCanvasElementById "canvas"
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
Could not match type
Maybe
with type
HookM t0
while trying to match type t1 t2
with type HookM t0 (Maybe (HookM t0 Unit))
while checking that expression
(bind ((apply liftEffect) (getCanvasElementById "canvas"))) (\mcanvas ->
(bind (...)) (\mcontext ->
...
)
)
has type HookM t0 (Maybe (HookM t0 Unit))
in value declaration drawOnCanvas
where t0 is an unknown type
t1 is an unknown type
t2 is an unknown type
I have a lot of Elm and a little Haskell experience but PureScript and Halogen are brand new to me. I also have a jumble of questions:
-
Am I on the right track? Am I going about this the right way or am I completely misunderstanding how Halogen & Hooks work?
-
Which part of the expression is not unifying correctly?
-
The types I’m expecting everything to have are below. Are these correct?
-- mcanvas <- liftEffect $ getCanvasElementById "canvas"
getCanvasElementById "canvas" :: Effect (Maybe CanvasElement)
liftEffect $ getCanvasElementById "canvas"
:: forall m. MonadAff m => m (Maybe CanvasElement)
mcanvas :: Maybe CanvasElement
-- mcontext <- liftEffect $ sequence $ getContext2D <$> mcanvas
getContext2D <$> mcanvas :: Maybe (Effect Context2D)
sequence $ getContext2D <$> mcanvas :: Effect (Maybe Context2D)
liftEffect $ sequence $ getContext2D <$> mcanvas
:: forall m. MonadAff m => m (Maybe Context2D)
mcontext :: Maybe Context2D
-- drawRect <$> mcontext
drawRect :: forall m. MonadAff m => Context2D -> m Unit
drawRect <$> mcontext :: forall m. MonadAff m => Maybe (m Unit)
pure unit :: forall m. MonadAff m => m Unit
-
It seems like the
UseEffect
type is only foruseTickEffect
anduseLifecycleEffect
- is that correct, or is it for any kind of effect? Example.Hooks.UseWindowWidth doesn’t seem to do anything special (as far as types) to callWindow.innerWidth
, which returns anEffect Int
. -
Even if this worked, will it never show anything because the call to
drawOnCanvas
comes before the canvas element? Or because it’s a tick effect, is the order irrelevant?
I think my next step will be to unsugar the whole Hooks.do
block and see if I see anything weird there.
Thanks for reading this far! Any help at all or any answers - full or partial - would be greatly appreciated!