My intention is to alternate the colour of a div between bright red and dark
red as a button gets pressed, starting with dark red.
I have this code:
{-# LANGUAGE
OverloadedStrings
#-}
module Main where
import Data.Map (Map)
import Reflex.Dom
main = mainWidget $ do
x <- greenButton
y <- toggle False x
let z = fmap style y
elDynAttr "div" z blank
style :: Bool -> Map String String
style b | b = "style" =: "height: 10ex; width: 10ex; background-color: #f00;"
| otherwise = "style" =: "height: 10ex; width: 10ex; background-color: #900;"
greenButton :: MonadWidget t m => m (Event t ())
greenButton = button "[ ]" -- Should be green but whatever.
It errors out thus:
• No instance for (Functor (Dynamic Spider))
arising from a use of ‘fmap’
• In the expression: fmap style y
In an equation for ‘z’: z = fmap style y
In the second argument of ‘($)’, namely
‘do { x <- greenButton;
y <- toggle False x;
let z = fmap style y;
elDynAttr "div" z blank }’
I certainly see an fmap for Dynamic in the quick reference,
though I am not sure the version of the reference and the version of the
reflex package I compile against are consistent.
This is the stack.yaml I use for building:
resolver: lts-7.19
compiler: ghcjs-0.2.1.9007019_ghc-8.0.1
compiler-check: match-exact
setup-info:
ghcjs:
source:
ghcjs-0.2.1.9007019_ghc-8.0.1:
url: http://ghcjs.tolysz.org/ghc-8.0-2017-02-05-lts-7.19-9007019.tar.gz
sha1: d2cfc25f9cda32a25a87d9af68891b2186ee52f9
extra-deps:
- reflex-dom-0.3
- ghcjs-dom-0.2.4.0
- ref-tf-0.4.0.1
- reflex-0.4.0.1
allow-newer: true
What am I doing wrong? And who the hell is this guy Spider?
The discussion below explains why Functor for Dynamic turned out to be a bad idea.
https://github.com/reflex-frp/reflex/pull/39
The problem with this instance is that it will evaluate
ftwice whenever the input dynamic changes: once to compute the newEventvalue, and once to compute the newBehaviorvalue. WithmapDyn, there is only a single computation, the result of both is shared. This is also whymapDynis monadic.
So the code would look like this:
main = mainWidget $ do
x <- greenButton
y <- toggle False x
z <- mapDyn style y -- monadic mapDyn instead of fmap
elDynAttr "div" z blank
On the issue of documentation, Quickref.md for version 0.4.0.1 is here and only references mapDyn.
The Quickref.md you linked to is the one for the future reflex-0.5 (the current develop branch), which is reworking Dynamic to have a Functor instance. See their wiki:
Why doesn't Dynamic have Functor/Applicative/Monad instances
Reflex is scheduled to get these instances in version 0.5. As of this writing the implementation is mostly complete and is undergoing final polish and testing before release and is currently available on github in reflex's develop branch.