无法通过动态映射:没有实例 (Functor (Dynamic Spider))

Cannot map through Dynamic: No instance for (Functor (Dynamic Spider))

我的意图是让 div 的颜色在亮红色和深红色之间交替 按下按钮时为红色,从深红色开始。

我有这个代码:

{-# 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.

因此出错:

• 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 }’

我当然在 quick reference 中看到 Dynamicfmap, 虽然我不确定参考的版本和 reflex 我编译的包是一致的。

这是 stack.yaml 我用来建造的:

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

我做错了什么?这个蜘蛛侠到底是谁?

下面的讨论解释了为什么 Functor 对于 Dynamic 结果是个坏主意。

https://github.com/reflex-frp/reflex/pull/39

The problem with this instance is that it will evaluate f twice whenever the input dynamic changes: once to compute the new Event value, and once to compute the new Behavior value. With mapDyn, there is only a single computation, the result of both is shared. This is also why mapDyn is monadic.


所以代码看起来像这样:

main = mainWidget $ do
    x <- greenButton
    y <- toggle False x
    z <- mapDyn style y      -- monadic mapDyn instead of fmap
    elDynAttr "div" z blank

关于文档问题,Quickref.md for version 0.4.0.1 is here且仅参考mapDyn

您链接到的 Quickref.md 是未来的 reflex-0.5(当前 develop 分支),它正在改造 Dynamic 以拥有 Functor 实例。 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.