在 reflex-dom 中,如何将值从动态传递到外部 javascript 函数 (FFI)
In reflex-dom, how to pass a value from a dynamic to a foreign javascript function (FFI)
我是 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
".value = "
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 转换为 m() 但无法弄清楚。这样做的最佳做法是什么?
函数 performEvent_
将强制执行 javascript 函数,但 performEvent_
需要 Event t (WidgetHost m ())
并且,正如错误消息指出的那样,您有一个Dynamic t (IO ())
.
您可以使用 updated
将您的 Dynamic t (IO ())
转换为 Event t (IO ())
并且您可以使用 fmap liftIO
将 IO ()
更改为 Event
到 WidgetHost m ()
给你留下 Event t (WidgetHost m ())
你可以传递给 performEvent_
这是修改后的代码。我删除了 testSet
的第一个参数和 testTB
中的元素创建,因为它们与 problem/solution 无关。我还添加了一些额外的类型声明。这些不是必需的,但可能会使事情更清楚。
{-# 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 "
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
我是 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
".value = "
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 转换为 m() 但无法弄清楚。这样做的最佳做法是什么?
函数 performEvent_
将强制执行 javascript 函数,但 performEvent_
需要 Event t (WidgetHost m ())
并且,正如错误消息指出的那样,您有一个Dynamic t (IO ())
.
您可以使用 updated
将您的 Dynamic t (IO ())
转换为 Event t (IO ())
并且您可以使用 fmap liftIO
将 IO ()
更改为 Event
到 WidgetHost m ()
给你留下 Event t (WidgetHost m ())
你可以传递给 performEvent_
这是修改后的代码。我删除了 testSet
的第一个参数和 testTB
中的元素创建,因为它们与 problem/solution 无关。我还添加了一些额外的类型声明。这些不是必需的,但可能会使事情更清楚。
{-# 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 "
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