Как получить HashMap (Object) из значения в Haskell, Aeson? - PullRequest
0 голосов
/ 17 октября 2018

Я пытаюсь привыкнуть к некоторым библиотекам на Haskell, решая некоторые проблемы с онлайн-практикой.

У меня есть некоторый код, который выводит это

Object (fromList [("ABC", String "123")])

Это также может быть

Object (fromList [("123", String "ABC")])
Object (fromList [(String "123", String "ABC")])
Object (fromList [("123", "ABC")])

, что мне нужно извлечь это "123"

использование .: с типом (.:) :: FromJSON a => Object -> Text -> Parser a для извлечения значения по заданному ключу приводит к возникновению этой ошибки

• Couldn't match type ‘Value’ with ‘HashMap Text Value’                                                         
  Expected type: Object
    Actual type: Value

Мое лучшее предположение - мне придется написать парсер, но я понятия не имею, какпродолжайте делать это или что искать.

Код, который выдал ошибку:

x <- (eitherDecode <$> simpleHttp url) :: IO (Either String DataSet)
  case x of
    Left er   -> print er
    Right an -> do
      let l = S.toList (data1 an)
      print $ l .: "ABC"

где DataSet определяется следующим образом

newtype DataSet = DataSet {
                   data1  :: Object
                   } deriving (Show, Generic)

Если бы язамените

print $ (Data.List.head l) .: "ABC"

на

print $ (Data.List.head l)

, я получу

Object (fromList [("ABC", String "123")])

Ответы [ 3 ]

0 голосов
/ 18 октября 2018

Один быстрый и грязный способ вывести вещи из типа Value - это

кодировать Value как ByteString

кодировать имеет тип encode :: ToJSON a => a -> ByteString

так вот в вашем коде

...
  case x of
    Left er   -> print er
    Right an -> do
      let l = S.toList (data1 an)
          x = (encode . snd) l  -- you can replace snd with fst if you want "ABC" instead of "123"
          y = decode x :: Maybe (HashMap String String)
          case y of
              Nothing -> print "got nothing"
              Just a -> print $ Data.HashMap.Strict.toList a

, который выведет список следующим образом:

[("123")]

Теперь вы можете извлекать значения с помощью простых функций.

Надеюсь, что это поможет.

Чтобы узнать больше о том, как лучше разбирать файл JSON, я бы порекомендовал дать https://artyom.me/aeson хорошее чтение.

0 голосов
/ 05 марта 2019

Вот несколько способов развернуть конструктор Object из типа данных Value.

Вы можете создать функцию для разворачивания:

unwrapValue :: Value -> Object
unwrapValue (Object x) = x
unwrapValue _ = error "No Object available"

Обратите внимание, что эта функция будетвернуть ошибку, потому что есть возможности, где Value не будет Object.

Кроме того, не смущайтесь, если Object является одновременно и конструктором Value, и типом в aeson!

Вы также можете развернуть inline, но это также небезопасно, то есть может вызвать ошибки во время выполнения.Например:

getNum :: Array -> Either String Scientific
getNum someArray = flip parseEither someArray $ \arr -> do
  let Just (Object obj) = arr !? 1 -- Unsafe unwrap Object constructor from Value (also unwraps Just constructor from Maybe)
  (Number num) <- obj .: "myNumber" -- Unsafe unwrap Number constructor from Value

  return num
0 голосов
/ 17 октября 2018

Object является одним из нескольких конструкторов типа Value

Haskell Constructor | JSON Syntax
Object              | {"key": "value"}
String              | "hello"
Number              | 123
Array               | [1, 2, 3]

Обратите внимание, что в этом случае конструктор Object не является конструктором типаObject.[Примечание в конце.]

Ошибка возникает при передаче Value какой-либо функции, ожидающей Object.Вам нужно будет определить, что должна делать программа, если она столкнется с каким-либо другим случаем.

Или, поскольку у вас есть data1 an :: Object, вы можете найти нужный ключ.Я не уверен, что это за тип S.toList, но вы, похоже, конвертируете свой Object в Value, а затем передаете его в .:, для чего требуется объект.

Последнее замечание: Object (fromList [("ABC", String "123")]) - это одно значение с одним объектом с одной парой ключ-значение.fromList - это способ создания объектов из их частей (вместо анализа строк JSON).

...