После некоторых копаний я нашел три обходных пути. Перейдите на дно, если хотите
лучший обходной путь до
toMap
земли.
По состоянию на 2019-05-05, в Дхалле нет возможности представлять карты, как они есть.
возможно с Aeson / YAML (хотя поддержка нативной функции toMap
скоро будет). Так что сейчас мы в основном должны использовать список однородных
записей. Это немного неуклюже, но, по крайней мере, ты получаешь нативный маршалинг.
Если мы хотим использовать список кортежей вместо карты, мы можем сделать это:
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE RecordWildCards #-}
module Tuple where
import Dhall
import qualified Data.Text as T
data MyType = MyType { env :: [MyTuple] }
deriving (Generic, Show)
instance Interpret MyType
newtype MyTuple = MyTuple (T.Text, T.Text)
deriving (Interpret, Show)
-- input auto "{env = [{_1= \"HOME\", _2 = \"foo\"}] }" :: IO MyType
Выше было адаптировано из этого
ответ , который показал способ
разбирать IP-адреса как 4-элементные кортежи.
Для разбора на карту мы можем сделать:
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
module MapA where
import Data.Map (Map)
import Data.Text (Text)
import Dhall
import qualified Data.Map
data MyType = MyType { env :: Map Text Text }
deriving (Generic, Show)
data KeyValue a = KeyValue { mapKey :: Text, mapValue :: a }
deriving (Generic, Show)
toMap :: [KeyValue a] -> Map Text a
toMap keyValues = Data.Map.fromList (map adapt keyValues)
where
adapt (KeyValue {..}) = (mapKey, mapValue)
instance Interpret MyType
instance Interpret a => Interpret (KeyValue a)
-- Wrap `Map` in a newtype if you want to avoid an orphan instance
instance Interpret a => Interpret (Map Text a) where
autoWith options = fmap toMap (autoWith options)
-- input auto "{env = [{mapKey = \"HOME\", mapValue = \"foo\"}] }" :: IO MapA.MyType
Выше было адаптировано из этого
комментарий . Идея состоит в том, чтобы сделать
записи, которые выглядят как { mapKey = X, mapValue = Y}
разбираемые, а затем
преобразовать любые списки таких записей в карту. Обратите внимание, как мы поддерживаем любую ценность
введите, а не просто текст (поэтому мы можем иметь env
in MyType
be Map Text Int
или
что-то еще, если бы мы хотели). Это решение имеет только 1 тип переменной a
для значений на карте, но я думаю, что можно сделать ключи более
также общий.
ОК, так что после некоторой настройки я получил следующее для компиляции, которое поддерживает оба
ключи и значения также должны быть общими:
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
module MapKV where
import Data.Map (Map)
import Data.Text (Text)
import Dhall
import qualified Data.Map
data MyType = MyType { env :: Map Text Text }
deriving (Generic, Show)
data MyTypeInts = MyTypeInts { envInts :: Map Integer Integer }
deriving (Generic, Show)
data KeyValue k v = KeyValue { mapKey :: k, mapValue :: v }
deriving (Generic, Show)
toMap :: Ord k => [KeyValue k v] -> Map k v
toMap keyValues = Data.Map.fromList (map adapt keyValues)
where
adapt (KeyValue {..}) = (mapKey, mapValue)
instance Interpret MyType
instance Interpret MyTypeInts
instance (Interpret k, Interpret v) => Interpret (KeyValue k v)
-- Wrap `Map` in a newtype if you want to avoid an orphan instance
instance (Ord k, Interpret k, Interpret v) => Interpret (Map k v) where
autoWith options = fmap toMap (autoWith options)
-- input auto "{env = [{mapKey = +1, mapValue = \"foo\"}] }" :: IO MapKV.MyType
-- input auto "{envInts = [{mapKey = +1, mapValue = -22 }] }" :: IO MapKV.MyTypeInts
Наконец, вот версия, в которой не используется экземпляр-сирота, использующий оболочку Env
newtype:
{-# LANGUAGE RecordWildCards #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE FlexibleInstances #-}
module MapKV where
import Data.Map (Map)
import Dhall
import qualified Data.Map
data MyType = MyType { env :: Env }
deriving (Generic, Show)
newtype Env = Env (Map Text Text)
deriving (Eq, Generic, Show)
data KeyValue k v = KeyValue { mapKey :: k, mapValue :: v }
deriving (Generic, Show)
toMap :: Ord k => [KeyValue k v] -> Map k v
toMap keyValues = Data.Map.fromList (map adapt keyValues)
where
adapt (KeyValue {..}) = (mapKey, mapValue)
instance Interpret MyType
instance (Interpret k, Interpret v) => Interpret (KeyValue k v)
instance Interpret Env where
autoWith options = fmap (Env . toMap) (autoWith options)
-- input auto "{env = [{mapKey = \"HOME\", mapValue = \"foo\"}] }" :: IO MapKV.MyType