Как заставить MonadError работать с ghcjs/reflex

Я изо всех сил пытаюсь скомпилировать следующую программу:

import           Data.Maybe
import qualified Data.Text       as T
import qualified Data.Text.IO    as T
import           Data.URLEncoded
import           Reflex.Dom

url :: T.Text
url = T.pack "parm1=one&parm2=two"

main = do
  mainWidget body

body :: MonadWidget t m => m ()
body  = el (T.pack "div") $ do
  -- let t = (T.pack "this program works if you replace the line below with this")
  t <- fmap (T.pack . fromMaybe "" . Data.URLEncoded.lookup "parm2") (importString (T.unpack url))
  text t

однако эта аналогичная версия работает с vanilla ghc

import           Data.Maybe
import qualified Data.Text       as T
import qualified Data.Text.IO    as T
import           Data.URLEncoded

url :: T.Text
url = T.pack "parm1=one&parm2=two"

main = do
  body

body  = do
  t <- fmap (T.pack . fromMaybe "" . Data.URLEncoded.lookup "parm2") (importString (T.unpack url))
  T.putStrLn t

Компилятор говорит, что что-то неоднозначно, и я не совсем уверен, как реализовать это для работы.

  The type variable ‘e0’ is ambiguous
  Relevant bindings include body :: m () (bound at reflex.hs:14:1)
  These potential instances exist:
    instance [safe] Control.Monad.Error.Class.MonadError e (Either e)
      -- Defined in ‘Control.Monad.Error.Class’
    ...plus 13 instances involving out-of-scope types
      instance [safe] Control.Monad.Error.Class.MonadError
                        GHC.IO.Exception.IOException IO
        -- Defined in ‘Control.Monad.Error.Class’
      instance [safe] (Monad m, Control.Monad.Trans.Error.Error e) =>
                      Control.Monad.Error.Class.MonadError
                        e (Control.Monad.Trans.Error.ErrorT e m)
        -- Defined in ‘Control.Monad.Error.Class’

К вашему сведению: я еще не полностью понял монады и легко пугаюсь этих ошибок. Помощь!


person bongsun    schedule 19.06.2018    source источник
comment
Помогает ли использование сигнатуры body::Widget(), от Reflex.Dom.Main? Или сделать main ::IO() ?   -  person trevor cook    schedule 19.06.2018
comment
Вместо этого я получаю следующее: • Ожидается еще один аргумент для ‘Widget()’ Ожидается тип, но ‘Widget()’ имеет вид ‘* -› *’ • В сигнатуре типа: body :: Widget()   -  person bongsun    schedule 20.06.2018


Ответы (1)


В версии ghc importString работает в контексте оператора IO монады do. importString может возвращать значение в монаде IO, так что компилятор доволен

В версии ghcjs importString работает в контексте оператора m монады do (m указано в объявлении body ). importString не может вернуть значение в монаде m, поэтому компилятор жалуется.

Вы можете обойти это, используя liftIO для изменения значения монады IO на значение монады m. Вот ваш код с этим изменением и несколькими другими изменениями, которые я сделал, чтобы помочь себе понять код.

import           Data.Maybe
import qualified Data.Text       as T
import           Data.URLEncoded as DU
import           Reflex.Dom
import           Control.Monad.Trans as CMT 

url :: T.Text
url = T.pack "parm1=one&parm2=two"

main = do
  mainWidget body

body :: MonadWidget t m => m ()
body  = el (T.pack "div") $ do
  let istr = CMT.liftIO $ DU.importString (T.unpack url)
  t <- fmap (T.pack . fromMaybe "" . DU.lookup "parm2") istr
  text t
person Dave Compton    schedule 19.06.2018