Проблема декодирования JSON из входных аргументов с помощью Aeson - PullRequest
0 голосов
/ 16 марта 2019

Я пытаюсь написать программу на Haskell, которая ожидает строку Json, предоставленную в качестве входных данных.Ожидаемый Json - это список Person объектов.Я хочу обработать случай, когда пользователь не предоставил ввод, по умолчанию Json пустого списка.Кажется, я сталкиваюсь с проблемой преобразования типов между ByteString и String.У меня действительно включен OverloadedStrings, но, похоже, это не помогает.Вот упрощенный код.

{-# LANGUAGE OverloadedStrings #-}
import GHC.Generics
import System.Environment
import Data.Aeson
import Data.Maybe (fromMaybe, listToMaybe)
import Data.Text (Text)

data Person = Person { pName :: Text, pAge :: Int } deriving (Show, 
Generic)
instance ToJSON Person
instance FromJSON Person

main :: IO (Maybe [Person])
main = do
  args <- getArgs
  arg1 <- pure $ (fromMaybe "[]" (listToMaybe args))
  -- let arg1 = "[{\"pName\": \"James\", \"pAge\": 30}]"
  return $ decode arg1 :: IO (Maybe [Person])

Ошибка, которую я получаю:

• Couldn't match type ‘[Char]’
                 with ‘Data.ByteString.Lazy.Internal.ByteString’
  Expected type: Data.ByteString.Lazy.Internal.ByteString
    Actual type: String
• In the first argument of ‘decode’, namely ‘arg1’
  In the second argument of ‘($)’, namely ‘decode arg1’
  In a stmt of a 'do' block:
      return $ decode arg1 :: IO (Maybe [Person])

Если я раскомментирую let arg1 для имитации того, каким должен быть arg1, то код компилируется.

1 Ответ

2 голосов
/ 16 марта 2019

Проблема в том, что getArgs возвращает [String], а не [ByteString].decode действительно хочет ByteString в качестве ввода.

OverloadedStrings не помогает с этим;это влияет только на строковые литералы в вашем коде, а не на внешние входные данные.Вот почему работает версия с жестко закодированным аргументом (let arg1 = "[{\"pName\": \"James\", \"pAge\": 30}]"): arg1 автоматически становится ByteString, чтобы заставить decode arg1 работать, но getArgs имеет несовместимый тип.

Одно из возможных исправленийкодировать строки командной строки в байтах, но, кажется, более простая альтернатива :

import System.Posix.Env.ByteString (getArgs)

, которая дает вам

getArgs :: IO [ByteString]

(Iфактически не проверял этот код, возможно, вам придется использовать decodeStrict вместо decode.)

...