2016-03-21 7 views
1

У меня есть следующий код из purescript-express (но вопрос более общий).Как объединить эти типы?

setHandler :: forall e. Handler e 
setHandler = do 
    idParam <- getRouteParam "id" 
    send "Yeah! " 

appSetup :: forall e. App e 
appSetup = do 
    get "/set/:id" setHandler 

setHandler потребность иметь данную подпись, как get определяется как

> :t get 
forall e r. 
(RoutePattern r) => r 
        -> HandlerM (express :: EXPRESS | e) Unit 
        -> AppM (express :: EXPRESS | e) Unit 

Однако теперь я хочу использовать следующую функцию в setHandler

getPointsSet :: forall f. String -> Aff (fs :: FS | f) Foobar 

, который даст мне следующее ошибка компилятора

[1/1 TypesDoNotUnify] src/Main.purs:31:5 

      v 
    31  send "Yeah! " 
     ^

    Could not match type 

    HandlerM 

    with type 

    Aff 

    while trying to match type HandlerM 
           (express :: EXPRESS 
           | _2 
           ) 
    with type Aff 
       (fs :: FS 
       | _0 
       ) 
    while checking that expression send "Yeah! " 
    has type Aff 
       (fs :: FS 
       | _0 
       ) 
       _1 
    in value declaration setHandler 

Я понимаю, что использование getPointsSet требует, чтобы setHandler также стал Aff, но я не могу подключить его к get.

Редактировать

Если я пытаюсь добавить liftAff как это было предложено в ответ ниже

setHandler :: forall e. Handler e 
setHandler = do 
    idParam <- getRouteParam "id" 
    liftAff $ getPointsSet "../some-data.csv" 
    send "Yeah! " 

Я получаю следующую ошибку

[1/1 NoInstanceFound] src/Main.purs:28:1 
    28 setHandler :: forall e. Handler e 
     ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ 
    No type class instance was found for 
    Control.Monad.Aff.Class.MonadAff (fs :: FS | _0) 
           (HandlerM (express :: EXPRESS | e0)) 

The instance head contains unknown type variables. Consider adding a type annotation. 
in value declaration setHandler 

Что мне нужно сделать, чтобы разрешить это?

ответ

5

Похоже, что HandlerM имеет экземпляр MonadAff, поэтому вы можете использовать liftAff. Как здесь:

setHandler :: forall e. Handler e 
setHandler = do 
    idParam <- getRouteParam "id" 
    liftAff $ getPointsSet "foo" 
    send "Yeah! " 

Ах, извините, строки не унифицировать без дополнительной аннотации appSetup и setHandler

обновленный вариант

appSetup :: forall e. App (fs :: FS|e) 
appSetup = 
    get "/set/:id" setHandler 

setHandler :: forall e. Handler (fs :: FS|e) 
setHandler = do 
    idParam <- getRouteParam "id" 
    liftAff $ getPointsSet "../some-data.csv" 
    send "Yeah! " 

Вы должны изменить main типа также

main :: forall e. Eff (express :: EXPRESS, fs :: FS|e) Unit 
+0

yup - все было. Сорт ;-) на самом деле то, что работает, просто не имеет подписи для setHandler – robkuz

1

Чтобы расширить на ответ Максим,

Ваш setHandler имеет тип forall e. Handler e, который эквивалентен HandlerM (express :: EXPRESS | e) Unit , который, в свою очередь эквивалентно HandlerM (Request -> Response -> Eff (express :: EXPRESS | e) Unit -> Aff (express :: EXPRESS | e) Unit). если взять на себя функцию из конструктора и кормить его с аргументами (как некоторая функция, вероятно, делает за кулисами), мы остались с Aff (express :: EXPRESS | e) Unit)

Ваш getPointsSet имеет тип forall f. String -> Aff (fs :: FS | f) Foobar

Так в основном наша проблема может быть уменьшена к этому: тип (express :: EXPRESS | e) не унифицировать с (fs :: FS | f), это означает, что для того, чтобы вызвать getPointsSet из setHandler, setHandler должен поставить String (вы указали "foo") и эффект FS который в настоящее время не поставляет.для его поставки подпись типа setHandler должна измениться, поэтому вместо Aff (express :: EXPRESS | e) Unit) мы хотим иметь Aff (express :: EXPRESS, fs :: FS | r). теперь точно такой же анализ должен быть сделан для main и setHandler, а также setHandler нужен эффект FS, который не поставляется. необходимо будет внести такое же изменение.

Я надеюсь, что это имеет смысл.