2015-08-14 7 views
0

Я только начинаю веб-разработку Haskell с помощью Spock, persistent и blaze-html.Ошибка типа Blaze-html внутри forM_ block

В одном из маршрутов, которые у меня есть, я хочу загрузить каждую строку в мои выбранные таблицы. Я делаю что-то вроде этого:

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)) 

Я скопировал 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 обертка от стойких к Споку, и если я просто хочу, чтобы выходной HTML, почему не может он проходит проверку типа?

Как устранить этот тип ошибки?

ответ

1

Отказ от ответственности: я не запускал ваш код.

runSQL Я знаю, что это оболочка от стойких к Споку

Ровно, и там лежит ваша проблема. Тип runSQL является:

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

тип результата, (HasSpock m, SpockConn m ~ SqlBackend) => m a, говорит нам, что runSQL дает результат в монаде Спок. Поэтому loadFlightSeat должен быть также вычислением монады Спока. Однако вы дали ему тип H.Html, который не имеет ничего общего с монадой Спока. Проблема, скорее всего, исчезнет, ​​если вы удалите ошибочный тип подписи 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.Htmlhappens to be a synonym for MarkupM(), с MarkupM является монадой, определяемой blaze. Как следствие, подпись, которую вы дали loadFlightSeat, приводит к компилятору, чтобы попытаться сопоставить Мону Спок с MarkupM.

+0

Спасибо, кажется, что перемещение loadFlightSeat работает. Хотя у меня все еще есть путаница в том, почему я должен переместить ее в монадию Спока (несмотря на то, что это такая же монада). Еще раз спасибо! – SanShin

+0

@SanShin Если я правильно понимаю ваше сомнение, кажется, вы смешиваете что-то, находящееся в 'do' -блоке какой-то монады, когда он находится в предложении' where' ниже 'do'-block. Для целей вашего вопроса не имеет значения, где вы определяете значение типа 'loadFlightSeat' (т. Е. Находится ли он на верхнем уровне,' where', выражение 'let' и т. Д.).То, что определяет, к какой монаде принадлежит значение, и как вам нужно использовать, - это его тип. – duplode