Let's assume you want to adopt the classic effectful approach to FRP. Now when you write:
x <- newSTRef 2
y <- newSTRef 3
z <- letSTRef (x + y)
you're really working in a pure fragment. Moreover, letSTRef, while attractive, is sort of on the wrong track.
Suppose we have two time-varying values mouseX and mouseY. They are both at least applicative values, i.e. f Int for some applicative, possibly even monadic, functor f.
They are also primitive, like the way a Haskell Int is primitive and involves hardware-wired details, meaning you'll do the actual implement at a lower level than the following:
We have a Euclidean distance function dist :: Int -> Int -> Int.
To track the distance of the mouse pointer from the origin, we'd write liftA2 dist mouseX mouseY :: f Int, thus deriving another time-varying Int.
Does this help clarify?