2017-11-25 2 views
4

저는 하스켈과 반사 신경을 처음 사용했지만 실제로는 언어를 좋아합니다. 나는 https://github.com/hansroland/reflex-dom-inbits/blob/master/tutorial.md을 사용하여 배우고 있으며 매우 도움이되었습니다.reflex-dom에서 동적 자바 스크립트 함수 (FFI)에 값을 전달하는 방법

현재 동적으로 값을 변경하고 요소를 만들고 동적 값이 변경 될 때마다 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!" 

이 컴파일시 오류가 발생합니다 : 나는 m()로 동적 변환하는 다양한 방법을 시도했지만 그것을 알아낼 수 없습니다

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) 

. 이 작업을 수행하는 가장 좋은 방법은 무엇입니까?

+0

'liftIO'ing을 시도해 보셨습니까? 'liftIO (testSet (GDTpToJSVal e) .GDT.pToJSVal) = << (샘플 $ 현재 dt)'? 나는 Reflex에 대한 전문가가 아니다. 그러나 이것은 검증하지 않으면된다고 말해야 만한다. – epsilonhalbe

+0

대다수의 오류는 생략 했으므로 대개 매우 유익합니다. 오류를 이해하면 해결 방법이 나와 있습니다. 좋은 대답은 문제를 해결하고 오류를 설명 할 것입니다 (낚시를하는 사람에게 모든 것을 가르쳐주세요 ...). – user2407038

+0

@epsilonhalbe liftM과 liftIO의 몇 가지 변형을 시도해 보았지만 제대로 작동하지 않는 것 같습니다. – Thanacles

답변

1

기능 performEvent_는 자바 스크립트 함수의 실행을 강제하지만 performEvent_ 오류 메시지가 지적한대로, 당신은 Dynamic t (IO())있어, Event t (WidgetHost m())을 원하고.

당신은 당신의 Dynamic t (IO())Event t (IO())로 변환 updated를 사용하고 performEvent_

여기 그 수정을 코드의에 당신이 통과 할 수있는 Event t (WidgetHost m()) 당신을 떠나 WidgetHost m()EventIO()을 변경 fmap liftIO을 사용할 수 있습니다 . 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 
+0

그게 효과가 있어요. 정말 고마워. 나는 여기서 몇 가지 것을 배웠다. – Thanacles

관련 문제