我正在尝试实现数据类型的show方法。
data OptionList a b = EmptyOpt | OptionList { optListHead :: a, optListTail :: b } deriving (Read)
instance (Show a, Show b) => Show (OptionList a b) where
show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}"
show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}"
show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}"
show EmptyOpt = ""
如果a
或b
中的一个具有由EmptyOpt构造的值,我希望OptionList不显示逗号。但编译器显示以下错误:
OptionList.hs:11:28:
Couldn't match expected type ‘b’
with actual type ‘OptionList t0 t1’
‘b’ is a rigid type variable bound by
the instance declaration at OptionList.hs:10:10
Relevant bindings include
show :: OptionList a b -> String (bound at OptionList.hs:11:9)
In the pattern: EmptyOpt
In the pattern: OptionList a EmptyOpt
In an equation for ‘show’:
show (OptionList a EmptyOpt) = "{" ++ (show a) ++ "}"
OptionList.hs:12:26:
Couldn't match expected type ‘a’
with actual type ‘OptionList t2 t3’
‘a’ is a rigid type variable bound by
the instance declaration at OptionList.hs:10:10
Relevant bindings include
show :: OptionList a b -> String (bound at OptionList.hs:11:9)
In the pattern: EmptyOpt
In the pattern: OptionList EmptyOpt b
In an equation for ‘show’:
show (OptionList EmptyOpt b) = "{" ++ (show b) ++ "}"
UPDATE :OptionList应该类似于无类型列表。
(+:) :: a -> b -> (OptionList a b)
infixr 5 +:
t1 +: t2 = OptionList t1 t2
因此,像0 +: "test" +: True
这样的列表定义为OptionList Int (OptionList String (OptionList Bool EmptyOpt))
,show
n为{0, {"test", {True}}}
答案 0 :(得分:6)
您的更新的更新。如果您愿意开启某些扩展程序,可以使其正常工作:
{-# LANGUAGE FlexibleInstances #-}
data EmptyOpt = EmptyOpt
data OptionList a b =
OptionList a b
deriving (Read)
instance (Show a, Show b) => Show (OptionList a b) where
show (OptionList a b) = "{ " ++ show a ++ ", " ++ show b ++ " }"
instance {-# OVERLAPPING #-} (Show a) => Show (OptionList a EmptyOpt) where
show (OptionList a EmptyOpt) = "{ " ++ show a ++ " }"
(+:) :: a -> b -> (OptionList a b)
infixr 5 +:
t1 +: t2 = OptionList t1 t2
test = 0 +: "test" +: True +: EmptyOpt
但我个人会尝试用类似
的东西data Option = B Bool | I Int | S String
data OptionsList = Empty | OptionsList Option OptionsList
您的问题是,实例主管((Show a, Show b) => Show (OptionList a b)
)表示您正在为Show
实施OptionList a b
,其中a
和b
是Show
的任何类型{ {1}}实例,但在您的实施中,您要求a
和b
实际上都是OptionList
类型。
也许您会将您的类型更改为更像普通列表:
data OptionList a
= EmptyOpt
| OptionList { optListHead :: a
, optListTail :: OptionList a}
deriving (Read)
然后你可以有一个实例:
instance (Show a) => Show (OptionList a) where
show (OptionList a EmptyOpt) = "{" ++ show a ++"}"
show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
show EmptyOpt = ""
答案 1 :(得分:3)
问题在于你的实例声明:
instance (Show a, Show b) => Show (OptionList a b) where show (OptionList a EmptyOpt) = "{" ++ (show a) ++"}" show (OptionList EmptyOpt b) = "{" ++ (show b) ++"}" show (OptionList a b) = "{"++ (show a) ++ ", " ++ (show b) ++"}" show EmptyOpt = ""
您使用dataconstructors 。因此,Haskell正确地推导出你实际定义show
超过OptionList (OptionList c d) (OptionList e f)
:毕竟EmptyOpt
是OptionList a b
的结构,所以你不能将它们用作参数,因为在您的实例的头部,您说您将使用通用OptionList a b
和a
定义b
的实例。
所以我不清楚你的目标是什么;将其修改为:
instance (Show a, Show b, Show c, Show d) => Show (OptionList (OptionList a b) (OptionList c d)) where
也无济于事,因为结构是递归的,因此您将定义具有无限递归深度的实例。
对我来说唯一合理的是你的数据定义是错误的,应该是这样的:
data OptionList a = EmptyOpt | OptionList { optListHead :: a, optListTail :: OptionList a }
在这种情况下,您可以将其定义为:
instance Show a => Show (OptionList a) where
show (OptionList a b) = "{"++ show a ++ ", " ++ show b ++"}"
show EmptyOpt = ""
或沿着这些方向的东西。
答案 2 :(得分:0)
我的想法是创建一个类型独立列表。这个列表的元素应该包含任何声明的类型。但我会放弃并做一些像C联盟的事情:
data Option = OptStr String | OptInt Int | OptBool Bool