Почему параметр может принимать любую конструкцию класса типов, но его значение не может быть построено условно? - PullRequest
5 голосов
/ 09 апреля 2020

Я довольно новичок в Haskell, но не в программировании, и я использую библиотеку req для выполнения HTTPS-запросов.

Чтобы сохранить некоторую общность , будет два типа запросов - один для создания документа (через HTTP POST) и другой для обновления документа (через HTTP PATCH, с использованием непустого моноида в параметре updateMask).

Я могу вывести HTTP-глагол из того, updateMask == mempty, но это не скомпилируется, потому что POST и PATCH - это разные объявления data (хотя оба действительны как первый параметр req, поскольку они являются экземплярами HttpMethod.

getSaveEventRequestResponse :: Text -> Option Https -> Document -> IO IgnoreResponse
getSaveEventRequestResponse authToken updateMask document =
  runReq defaultHttpConfig $
  req
    (if updateMask == mempty
       then POST
       else PATCH)
    (https "test.example.com" /: "api" /: "projects" /: "myproject")
    (ReqBodyJson document)
    ignoreResponse $
  oAuth2Bearer (encodeUtf8 authToken) <> updateMask

Если я поменяю условие if на любое из POST или PATCH код компилируется без ошибок.

Есть ли способ заставить компилятор разрешить этот условный ответ или мне нужно дублировать эту функцию, одну с использованием варианта POST, а другую с использованием PATCH?

Редактировать в интересах любого, кто придет к этому и попытается использовать тот же код:

Условие, которое я использовал (updateMask == mempty), на самом деле здесь недопустимо, но это не имеет отношения к вопросу. Вопрос стоит, если это условие заменено на True или False.

Изменить 2 относительно связанного вопроса. Хотя я теперь, получив ответ, вижу, насколько тесно он связан, он полагается на то, что уже рассмотрел частичное применение. Хотя принцип тот же, введение частичного применения затрудняет начинающему с Haskell применять ответ в этом контексте.

1 Ответ

8 голосов
/ 09 апреля 2020

Возможным решением является использование

(if updateMask == mempty then req POST else req PATCH) other args here

Это потому, что

req :: (MonadHttp m, HttpMethod method, HttpBody body, 
        HttpResponse response, 
        HttpBodyAllowed (AllowsBody method) (ProvidesBody body))     
    => method   
    -> Url scheme   
    -> body 
    -> Proxy response   
    -> Option scheme    
    -> m response

Теперь AllowsBody POST и AllowsBody PATCH равны, поскольку оба определены как 'CanHaveBody , Таким образом, req POST и req PATCH могут иметь общий тип:

req POST, req PATCH 
    :: (MonadHttp m, HttpBody body, 
        HttpResponse response, 
        HttpBodyAllowed 'CanHaveBody (ProvidesBody body))    
    => Url scheme   
    -> body 
    -> Proxy response   
    -> Option scheme    
    -> m response

Имея одинаковый тип, они могут использоваться в двух ветвях одного и того же if then else.

...