Как прочитать/перевести pickle файлы в Haskell?

Рейтинг: 1Ответов: 1Опубликовано: 01.03.2023

У меня есть пикл-файл с данными, содержащими листы, дикты, строки и числа. Как можно перевести эти данные в формат, распознаваемый хаскелем? Т.е. в формат любой из библиотек для сериализации (чем проще, тем лучше). Может есть какие-то готовые решения, которые позволят сразу из хаскеля читать пикл-файлы?

Изначальная задача состоит в том, чтобы полученные питоном данные обработать в хаскеле и передать обратно в питоновский скрипт. Если есть варианты без пикла, то тоже интересно.

Ответы

▲ 2

Формат pickle слишком привязан к python, чтобы его можно было уверенно использовать где-либо еще.

В вашем случае вполне подойдет json.

Из за того, что Haskell статически типизированный язык без иерархии типов, нативные списки и подобные контейнеры обычно гомогенные, т.е. с однотипными элементами.

Поэтому есть 2 варианта использования json

1. Храним в json только данные удобно представимые типами данных Haskell

При этом структура файла четко определена и все поля совпадают по типам. Для (де)кодирования таких данных в библиотеке уже есть удобные средства

{-# LANGUAGE DeriveGeneric #-}

import Data.Aeson
import GHC.Generics

data Record = Record
  { num :: Int
  , str :: String
  , nums :: Maybe [Double]
  } deriving (Generic, Show)

instance FromJSON Record where
  parseJSON = genericParseJSON defaultOptions { rejectUnknownFields = True }

instance ToJSON Record where
  toEncoding = genericToEncoding defaultOptions { omitNothingFields = True }
ghci> :set -XOverloadedStrings
ghci> eitherDecode "{\"num\": 1.1}" :: Either String Record
Left "Error in $.num: parsing Int failed, value is either floating or will cause over or underflow 1.1"
ghci> eitherDecode "{\"num\": \"1\"}" :: Either String Record
Left "Error in $.num: parsing Int failed, expected Number, but encountered String"
ghci> eitherDecode "{\"num\": 1, \"str\": \"x\", \"someField\": true}" :: Either String Record
Left "Error in $: parsing Main.Record(Record) failed, unknown fields: [\"someField\"]"
ghci> eitherDecode "{\"num\": 1, \"str\": \"x\"}" :: Either String Record
Right (Record {num = 1, str = "x", nums = Nothing})
ghci> eitherDecode "{\"num\": 1, \"str\": \"x\", \"nums\": [1,2,3]}" :: Either String Record
Right (Record {num = 1, str = "x", nums = Just [1.0,2.0,3.0]})
ghci> encode Record { num = 1, str = "test", nums = Nothing }
"{\"num\":1,\"str\":\"test\"}"
ghci> encode Record { num = 1, str = "test", nums = Just [1,2,3] }
"{\"num\":1,\"str\":\"test\",\"nums\":[1.0,2.0,3.0]}"

2. Используем смешанный тип Value для хранения произвольной json-структуры

-- прибавляем единицу ко всем числам внутри json
nestedPlus1 :: Value -> Value
nestedPlus1 (Number x) = Number (x + 1)
nestedPlus1 (Array xs) = Array (nestedPlus1 <$> xs)
nestedPlus1 (Object kvs) = Object (nestedPlus1 <$> kvs)
nestedPlus1 x = x
ghci> :set -XOverloadedStrings
ghci> eitherDecode "1" :: Either String Value
Right (Number 1.0)
ghci> eitherDecode "[1, true]" :: Either String Value
Right (Array [Number 1.0,Bool True])
ghci> eitherDecode "[1, true, {\"key\": \"value\"}]" :: Either String Value
Right (Array [Number 1.0,Bool True,Object (fromList [("key",String "value")])])

ghci> encode . nestedPlus1 <$> eitherDecode "[1, true, [2, 3, {\"x\": 4}]]"
Right "[2,true,[3,4,{\"x\":5}]]"
ghci> :set -XOverloadedStrings
ghci> encode 1
"1"
ghci> encode ["x","y"]
"[\"x\",\"y\"]"
ghci> encode $ object ["x" .= 1, "y" .= True, "z" .= [Number 1, String "x"]]
"{\"x\":1,\"y\":true,\"z\":[1,\"x\"]}"