0

我刚刚开始使用 Spock、persistent 和 blaze-html 进行 Haskell Web 开发。

在我拥有的一条路线中,我想加载我选择的表中的每一行。我做这样的事情:

  get ("/show/flight/" <//> (var :: Var Integer)) $ \f -> requireUser $ \(_, l) -> do
     fs <- runSQL $ loadFlightInfos f

     case fs of
        [] -> blaze $ template False (showResultAlertBar False "Oops, something went wrong! Please try again.")
        _  -> blaze $ template True (H.toHtml $ usersUsername l) loadFlightSeat

           where
              loadFlightSeat :: H.Html
              loadFlightSeat =
                 forM_ fs $ \fs' -> do
                    sid <- runSQL $ getSeatIdByFlight fs' c

                    case sid of
                       Nothing  -> H.div H.! A.class_ "alert alert-danger" $ "Oops, something went wrong! Please try again."
                       Just rid -> H.a H.! A.href (H.toValue $ "/flight/seat/" <> show c <> "/" <> show (fromIntegral $ (fromSqlKey . entityKey) sid)) H.! A.class_ "btn btn-theme" $ H.toHtml fs'

loadFlightInfos有类型:

Integer -> SqlPersistM [Entity Flight]

和 getSeatIdByFlight:

T.Text -> Integer -> SqlPersistM (Maybe (Entity Flight))

我从 Spock 的博客示例应用程序中复制runSQL,它是这样的:

runSQL :: (HasSpock m, SpockConn m ~ SqlBackend) => SqlPersistT (NoLoggingT (ResourceT IO)) a -> m a
runSQL action = runQuery $ \conn -> runResourceT $ runNoLoggingT $ runSqlConn action conn

我得到的类型错误:

Couldn't match expected type ‘SqlBackend’
        with actual type ‘SpockConn Text.Blaze.Internal.MarkupM’
In the expression: runSQL
In a stmt of a 'do' block:
   sid <- runSQL $ getSeatIdByFlight fs' c

我仍然不明白这种类型错误,因为我知道runSQL它是从持久化到 Spock 的包装器,如果我只是想输出 HTML,为什么它不能通过类型检查?

如何解决此类型错误?

4

1 回答 1

1

免责声明:我没有运行您的代码。

我知道runSQL是从持久性到 Spock 的包装器

没错,这就是你的问题。的类型runSQL是:

runSQL :: (HasSpock m, SpockConn m ~ SqlBackend)
       => SqlPersistT (NoLoggingT (ResourceT IO)) a -> m a

结果类型 ,(HasSpock m, SpockConn m ~ SqlBackend) => m a告诉我们runSQL在 Spock monad 中给出了一个结果。因此,loadFlightSeat也应该是一个 Spock monad 计算。但是,您给它 type H.Html,这与 Spock monad 无关。loadFlightSeat如果您删除错误的类型签名并相应地调整您的使用,该问题可能会消失loadFlightSeat

     flightSeat <- loadFlightSeat -- Returns an H.Html value in the Spock monad.
     case fs of
        [] -> blaze $ template False (showResultAlertBar False "Oops, something went wrong! Please try again.")
        _  -> blaze $ template True (H.toHtml $ usersUsername l) flightSeat

PS:你得到的类型错误......

Couldn't match expected type ‘SqlBackend’
        with actual type ‘SpockConn Text.Blaze.Internal.MarkupM’
In the expression: runSQL
In a stmt of a 'do' block:
   sid <- runSQL $ getSeatIdByFlight fs' c

...异常奇怪,因为它H.Html 恰好是 的同义词MarkupM (),并且MarkupM是由 . 定义的单子blaze。因此,您提供的签名会loadFlightSeat导致编译器尝试将 Spock 的 monad 与MarkupM.

于 2015-08-14T03:29:02.780 回答