我尝试为一个使用列表的解码器泛型地派生示例。当我在一个有多个选择器的类型上使用derive (Generic)
时,选择器被关联到一个树结构中,例如对于四个构造器,它看起来像((S1 a :*: S1 b) :*: (S1 c :*: S1 d))
。我不知道如何为这个写示例,即使我已经弄清楚了选择器如何关联的算法。
最小示例:
{-# language DefaultSignatures, DeriveGeneric #-}
import Data.List
import GHC.Generics
import Numeric.Natural
data Foo = Foo Int Int Int Int
deriving (Generic, Show)
data Bar = Bar Int Int
deriving (Generic, Show)
class Codec a where
encode :: a -> [Int]
default encode :: (Generic a, Codec' (Rep a)) => a -> [Int]
encode = encode' . from
decode :: [Int] -> a
default decode :: (Generic a, Codec' (Rep a)) => [Int] -> a
decode = to . decode'
class Codec' f where
encode' :: f a -> [Int]
decode' :: [Int] -> f a
instance Codec Int where
encode = singleton
decode = head
instance Codec c => Codec' (K1 i c) where
encode' (K1 x) = encode x
decode' x = K1 (decode x)
instance Codec' f => Codec' (M1 i t f) where
encode' (M1 x) = encode' x
decode' x = M1 (decode' x)
instance (Codec' f, Codec' g) => Codec' (f :*: g) where
encode' (x :*: y) = encode' x <> encode' y
decode' (x:xs) = decode' (singleton x) :*: decode' xs
instance Codec Foo
instance Codec Bar
main :: IO ()
main = do
print (decode $ encode (Bar 1 2) :: Bar)
print (decode $ encode (Foo 1 2 3 4) :: Foo)
字符串
输出量:
Bar 1 2
Foo 1 generic.hs: Prelude.head: empty list
CallStack (from HasCallStack):
error, called at libraries/base/GHC/List.hs:1644:3 in base:GHC.List
errorEmptyList, called at libraries/base/GHC/List.hs:87:11 in base:GHC.List
badHead, called at libraries/base/GHC/List.hs:83:28 in base:GHC.List
head, called at /private/tmp/generic.hs:26:14 in main:Main
型
预期输出:
Bar 1 2
Foo 1 2 3 4
型
1条答案
按热度按时间unhi4e5o1#
注解中提出的解决方案可能会起作用,但如果你不想那么麻烦,你想重新实现你的
decode
/decode'
对,这样它们就更像是对[Int]
输入流的解析器,当它们完成工作时返回流中“未使用”的部分。也就是说,你的泛型类应该看起来像这样:字符串
这样你就可以写:
型
其中第一子
decode'
可以确定在对剩余部分调用第二子decode'
之前要吸收多少输入流。完全重写的示例:
型