2015-07-01 5 views
1

Я пытаюсь использовать монаду IO в приложении Spock. Следующий код не компилируется:Несоответствие типа Monad

get "api/entities" $ do 
    entities <- loadEntities 
    let e1 : xs = entities 
    text $ note e1 

loadEntities имеет тип IO [Entity]

ошибка Couldn't match type ‘ActionT IO()’ with ‘t0 -> IO b0’

ли Спок с помощью монады, кроме ввода-вывода? Если да, как мне получить результат loadEntities?

+1

Вы уверены, что loadEntities не что-то вроде 'loadEntities :: а -> IO b' Вы будете также, вероятно, нужно что-то вроде 'объекты <- liftIO $ loadEntites arg' – DiegoNolan

+0

loadEntities кажется' IO [Entities] ', согласно компилятору. liftIO работал! Это необходимо, потому что это происходит в монаде ActionT? И стандартная лифта в библиотеке трансформаторов? Благодарю. – davenportw15

+1

Да, подставка 'liftIO' является библиотекой трансформаторов под' Contol.Monad.Class.IO'. – DiegoNolan

ответ

4

Написание ответа, чтобы люди могли видеть лучшее объяснение.

Если вы посмотрите на get, у него есть тип.

get :: MonadIO m => SpockRoute -> ActionT m() -> SpockT m() 

ActionT является монадой трансформатора и требует во внутренней монады, чтобы иметь экземпляр MonadIO. Если мы посмотрим на класс типов MonadIO имеет функцию

liftIO :: IO a -> m a 

Это означает, что каждый, что вы называете выполнять функции типа IO a в этом стеке с помощью liftIO. ActionT также имеет экземпляр MonadIO и который является тем, который вы используете здесь для вызова функции ввода-вывода. Таким образом, чтобы позвонить loadEntities вам пришлось

entities <- liftIO loadEntities 

Если конец вызова определенной функции так много вы можете создать отдельный модуль импорта он квалифицирован и экспортировать более дружественным.

module Lifted (loadEntities) where 

import qualified SomeModule as IO 

loadEntities :: MonadIO m => m Entities 
loadEntities = liftIO IO.loadEntities 

Это сделает это так, вы не всегда использовать liftIO

Смежные вопросы