好的,这是我上一个问题(Generically) Build Parsers from custom data types?的延续。我接受了这个建议并决定使用generic-sop构建我的解析器,直到现在一切都很顺利。
我需要稍微扩展我的实现,以便处理更复杂的情况。即,请考虑这两个data
定义,其中B
建立在A
之上:
data A = A String Int
data B = B A Double
为了通常解析所有data
结构,我定义了以下class
:
class HasSimpleParser f where
getSimpleParser :: Parser f
class Parsable f where
getParser :: Parser f
class GenericallyParsable f where
getGenericParser :: Parser f
Int, String, Double
等原始类型可以很容易地成为HasSimpleParser
的实例。然后,通过执行
A
的数据结构设为Parsable
的实例
instance (Generic r, Code r ~ '[xs], All HasSimpleParser xs) => Parsable r where
getParser = to . SOP. Z <$> hsequence (hcpure (Proxy @HasSimpleParser) getSimpleParser)
我引入了类GenericallyParsable
来解析像B
这样的数据结构。所以我做了以下几点:
instance (Generic r, Code r ~ '[xs], All Parsable xs) => GenericallyParsable r where
getGenericParser = to . SOP. Z <$> hsequence (hcpure (Proxy @Parsable) getParser)
这个难题的最后几部分是解析功能:
parseA :: InputStream ByteString -> IO A
parseA = parseFromStream (getGenericParser @A)
parseB :: InputStream ByteString -> IO B
parseB = parseFromStream (getGenericParser @B)
但是,代码无法编译,我收到以下错误:
• Couldn't match type ‘'['[Char, [Char]]]’ with ‘'[]’
arising from a use of ‘getGenericParser’
• In the first argument of ‘parseFromStream’, namely
‘(getGenericParser @A)’
In the expression: parseFromStream (getGenericParser @A)
In an equation for ‘parseA’:
parseA = parseFromStream (getGenericParser @A)
那么我应该如何修改代码才能工作?
答案 0 :(得分:2)
我认为GenericallyParsable
类型类没有必要。
只需为HasSimpleParser
上的A
定义一个Parsable
实例:
instance HasSimpleParser A where
getSimpleParser = getParser
如果您最终为记录声明了此类型的许多实例,则可以使用{-# language DefaultSignatures #-}
并将HasSimpleParser
的定义更改为
class HasSimpleParser c where
getSimpleParser :: Parser c
default getSimpleParser :: Parsable c => Parser c
getSimpleParser = getParser
现在在记录实例中你只需要写:
instance HasSimpleParser A
事实上,即使是HasSimpleParser
和Parsable
之间的区别也许是不必要的。单个HasParser
类型类包含基本类型和复合类型的实例就足够了。默认实现将使用generics-sop并且需要(Generic r, Code r ~ '[xs], All HasParser xs)
约束。
class HasParser c where
getParser :: Parser c
default getParser :: (Generic c, Code c ~ '[xs], All HasParser xs) => Parser c
getParser = ...generics-sop code here...