5

我是 Haskell 和 reflex-dom 的新手,但我真的很喜欢这种语言。我一直在使用https://github.com/hansroland/reflex-dom-inbits/blob/master/tutorial.md来学习,它非常有帮助。

我目前正在尝试创建一个函数,该函数接受动态并创建一个元素并在每次动态值发生变化时调用 FFI 函数。这是我正在尝试做的简化版本。

{-# LANGUAGE OverloadedStrings #-}
import Data.Text as T
import qualified GHCJS.DOM.Types as GDT
import GHCJS.Types
import Reflex.Dom

foreign import javascript safe
  "$1.value = $2"
  testSet :: JSVal -> JSVal -> IO()

testTB :: DomBuilder t m => Dynamic t T.Text -> m ()
testTB dt = do
  (e, _) <- elAttr' "input" ("type" =: "text") blank
  bob <- (testSet (GDT.pToJSVal e) . GDT.pToJSVal) <$> dt
  return ()

main = mainWidget $ testTB $ constDyn "Hello World!"

这会导致编译时错误:

reflex-canvas.hs:14:10: error:
    • Couldn't match type ‘m’ with ‘Dynamic t’
      ‘m’ is a rigid type variable bound by
        the type signature for:
          testTB :: forall t (m :: * -> *).
                    DomBuilder t m =>
                    Dynamic t Text -> m ()
        at reflex-canvas.hs:11:11
      Expected type: m (IO ())
        Actual type: Dynamic t (IO ())
    • In a stmt of a 'do' block:
        bob <- (testSet (GDT.pToJSVal e) . GDT.pToJSVal) <$> dt
      In the expression:
        do { (e, _) <- elAttr' "input" ("type" =: "text") blank;
             bob <- (testSet (GDT.pToJSVal e) . GDT.pToJSVal) <$> dt;
             return () }
      In an equation for ‘testTB’:
          testTB dt
            = do { (e, _) <- elAttr' "input" ("type" =: "text") blank;
                   bob <- (testSet (GDT.pToJSVal e) . GDT.pToJSVal) <$> dt;
                   return () }
    • Relevant bindings include
        e :: Element EventResult (DomBuilderSpace m) t
          (bound at reflex-canvas.hs:13:4)
        dt :: Dynamic t Text (bound at reflex-canvas.hs:12:8)
        testTB :: Dynamic t Text -> m () (bound at reflex-canvas.hs:12:1)

我尝试了各种方法将 Dynamic 转换为 am() 但无法弄清楚。这样做的最佳做法是什么?

4

1 回答 1

3

该函数performEvent_将强制执行一个 javascript 函数,但performEvent_需要一个Event t (WidgetHost m ())并且,正如错误消息指出的那样,你有一个Dynamic t (IO ()).

您可以使用updated将 your 转换Dynamic t (IO ())为 anEvent t (IO ())并且可以使用fmap liftIOIO ()in the更改Event为 aWidgetHost m ()离开您Event t (WidgetHost m ()),您可以将其传递给performEvent_

这是您进行这些修改的代码。我删除了第一个参数testSet和里面的元素创建,testTB因为它们与问题/解决方案无关。我还添加了一些额外的类型声明。这些不是必需的,但可能会使事情更清楚。

{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
import Data.Text as T (Text)
import qualified GHCJS.DOM.Types as GDT (pToJSVal)
import GHCJS.Types (JSVal)
import Reflex.Dom
import Control.Monad.Trans (liftIO)

foreign import javascript safe
  "console.log $1"
  testSet :: JSVal -> IO()

testTB :: forall t m.  MonadWidget t m => Dynamic t T.Text -> m ()
testTB dt = do 
    let bob :: Dynamic t (IO ())
        bob = (testSet.(GDT.pToJSVal)) <$> dt  

        bobIOEvent :: Event t (IO ())
        bobIOEvent = updated bob

        bobWidgetHostEvent :: Event t (WidgetHost m ())
        bobWidgetHostEvent = fmap liftIO bobIOEvent

    performEvent_ bobWidgetHostEvent

main = mainWidget $ do
    ti <- textInput def 
    let dt = value ti
    testTB dt
于 2017-11-27T04:44:39.010 回答