我有一个与Show相同的类,我想为每个元组类型创建一个此类的实例。通常这是通过为每个元组类型单独编写实例来完成的
instance (Show a, Show b) => Show (a,b) where
showsPrec _ (a,b) s = show_tuple [shows a, shows b] s
instance (Show a, Show b, Show c) => Show (a, b, c) where
showsPrec _ (a,b,c) s = show_tuple [shows a, shows b, shows c] s
instance (Show a, Show b, Show c, Show d) => Show (a, b, c, d) where
showsPrec _ (a,b,c,d) s = show_tuple [shows a, shows b, shows c, shows d] s
...
为每个元组类型编写一个实例会导致大量样板文件,并且很容易看到所有showPrec
实现之间共享的通用模式。为了避免这种样板,我想我可以使用Scrap你的样板中的Data.Generics并实现折叠元组,比如
showTuple = intercalate " " . gmapQ ("" `mkQ` show)
但showTuple
由于某种原因不起作用
> showTuple (1,2)
" "
我认为问题在于它show
是多态的,因为如果我专攻showTuple
它,它就会起作用
showTupleInt = intercalate " " . gmapQ ("" `mkQ` (show :: Int -> String))
> showTupleInt (1::Int,2::Int)
"1 2"
我检查了gshow的代码,它的功能与我需要的类似,但我不知道它是如何工作的。如果我尝试将其代码导入 GHCI,则会收到错误消息:
> let gshows = (\t -> showChar '('
. (showString . showConstr . toConstr $ t)
. (foldr (.) id . gmapQ ((showChar ' ' .) . gshows) $ t)
. showChar ')'
) `extQ` (shows :: String -> ShowS)
<interactive>:262:59:
Could not deduce (a ~ d)
from the context (Data a)
bound by the inferred type of
gshows :: Data a => a -> String -> String
at <interactive>:(259,5)-(264,44)
or from (Data d)
bound by a type expected by the context:
Data d => d -> String -> String
at <interactive>:262:33-65
`a' is a rigid type variable bound by
the inferred type of gshows :: Data a => a -> String -> String
at <interactive>:259:5
`d' is a rigid type variable bound by
a type expected by the context: Data d => d -> String -> String
at <interactive>:262:33
Expected type: d -> String -> String
Actual type: a -> String -> String
In the second argument of `(.)', namely `gshows'
In the first argument of `gmapQ', namely
`((showChar ' ' .) . gshows)'
In the second argument of `(.)', namely
`gmapQ ((showChar ' ' .) . gshows)'
所以我有两个问题:
- 有什么问题,
showTuple
我该如何修复它,使其适用于任何大小的元组 - 它是如何
gshow
工作的,为什么如果我在 GHCI 上导入它的代码会出现这个错误?
编辑:我正在学习Data.Generics
,总的来说是 SYM,所以我想使用那个模块。只有当它仅使用该模块时,我才会接受答案。谢谢。