Haskell Swagger Lens с автогенерацией - PullRequest
0 голосов
/ 03 мая 2018

У меня есть следующий код:

import Control.Lens ((&), (.~), (?~), (%~))
import Data.Swagger (Swagger)
import Data.Swagger.Lens (paths, operationId, info, description)
import qualified Data.HashMap.Strict.InsOrd as InsOrdHashMap
import Data.Text (Text(..), pack)

genOpIds :: Swagger -> Swagger
genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & operationId ?~ (pack "hello"))

Генерирование следующей ошибки компиляции:

    • No instance for (Data.Swagger.Lens.HasOperationId
                         Data.Swagger.Internal.PathItem (Maybe Text))
        arising from a use of ‘operationId’
    • In the first argument of ‘(?~)’, namely ‘operationId’
      In the second argument of ‘(&)’, namely
        ‘operationId ?~ (pack "hello")’
      In the expression: v & operationId ?~ (pack "hello")
   |
12 | genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & operationId ?~ (pack "hello"))
   |                                                           ^^^^^^^^^^^

Мне немного сложно диагностировать, так как я думаю, что makeLenses используется для генерации экземпляров класса. Я немного изо всех сил, чтобы увидеть, как это отличается от следующего (который прекрасно компилируется):

writeInfoTitle :: Swagger -> Swagger
writeInfoTitle = info.description ?~ (pack "whatever description")

так как иерархия типов похожа внизу. Я подозреваю, что здесь есть фундаментальное понимание, которого мне не хватает, но я прочитал руководство по линзам, включая раздел об обходах; различные биты кода чванства слуги и некоторые другие примеры, которым так и не удалось это выяснить.

Чтобы легко восстановить сообщение об ошибке, вы можете клонировать следующий репозиторий и stack build:

https://github.com/msk-/improved-spork

1 Ответ

0 голосов
/ 04 мая 2018

Отказ от ответственности: я никогда не использовал Swagger. Однако, глядя на документацию по нему, я вижу следующий элемент в типе Swagger:
_swaggerPaths :: InsOrdHashMap FilePath PathItem - соответствует объективу paths.
Глядя на определение PathItem, вы обнаруживаете, что это не экземпляр HasOperationId - он сам состоит из

PathItem     
  _pathItemGet :: Maybe Operation   
  _pathItemPut :: Maybe Operation   
  _pathItemPost :: Maybe Operation  
  _pathItemDelete :: Maybe Operation    
  _pathItemOptions :: Maybe Operation   
  _pathItemHead :: Maybe Operation  
  _pathItemPatch :: Maybe Operation 
  _pathItemParameters :: [Referenced Param]

, который, кажется, наводит на мысль о том, что вам не хватает композиции Lens в
(\k v -> v & (??? . operationId) ?~ (pack "hello")); что-то похожее на
(\k v -> v & (itemGet . operationId) ?~ (pack "hello"))

РЕДАКТИРОВАТЬ: Похоже, что то, что вы пытаетесь достичь (настройка простой операции пути), может быть легко сделано с помощью экземпляра Monoid записи PathItem, например:

genOpsId = paths %~ InsOrdHashMap.mapWithKey (\k v -> v & get ?~ (mempty & operationId ?~ (pack "hello")))



EDIT # 2: В соответствии с запросом, есть один способ перебрать поля записи PathItem и установить идентификатор операции из тех, которые присутствуют.
Для справки, я почти уверен, что есть способ, способ, более чистый способ сделать это, но здесь идет.

dokey :: PathItem -> PathItem
dokey v = foldl 
  (\acc nv -> acc & nv %~ (fmap $ operationId ?~ (pack "hello")))
  v 
  [get, put, post, delete, options, head_, patch]  

genOpIds :: Swagger -> Swagger
genOpIds = paths %~ InsOrdHashMap.mapWithKey (\k -> doKey)


Надеюсь, это поможет! :)

...