![](/img/trans.png)
[英]How to create list of instances deriving from a base class that implements interface?
[英]Deriving length function from List in data class
我有一个包含两个别名的数据类: String
和[String]
,即[Char]
和[[Char]]
。 目前它派生Eq
和Show
:
data BashVar = BashString String | BashArray [String] deriving (Eq,Show)
为什么它不能也从[_]
派生出来,或者为什么却调用了通用列表类型?
我只希望能够在类的实例上使用列表函数,特别是length
。
列表没有类别。 length
简单定义为:
length :: [a] -> Int
不(正如我想像的那样):
class ListLike l where
length :: l a -> Int
列表中最接近的类可能是Foldable
: http : //hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html但这并没有定义length
,只是各种折叠。
除此之外,如果有一个列表类,它可能仍将允许内部类型变化,如上面的示例所示。 您的BashVar
类不允许列表中使用任何类型,而是固定为String列表。 因此,即使存在ListLike
,您也无法支持它(并且出于相同的原因也无法派生Foldable
)。
Eq
和Show
都是类型类 ,而[]
是数据类型 。 如果查看(==)
的类型,则为Eq a => a -> a -> Bool
,而length
为[a] -> Int
。 不同之处在于,第一个具有类型分类约束Eq a
,而第二个则完全不依赖于类型分类约束,仅依赖于数据类型[a]
。 不幸的是,无法使默认length
与自定义数据类型一起使用。
最好的选择是定义自己的功能:
bashLength :: BashVar -> Int
bashLength (BashString s) = length s
bashLength (BashArray xs) = length xs
从您的问题和评论中,您在说些废话,如下所示:
I have a data class
Why can't it derive also from [_] or however the generic list type is called?
BashVar is an instance of [a]
可以很容易地发现您正在尝试“跳动”该语言,而无需花费最少的时间来阅读最基本的教程。
至少让您熟悉“了解Haskell”的“类型和类型分类”一章 ,才能消除您在此处提出的所有问题。 否则就不可能对其他事物进行解释,因为该语言及其大多数概念与您可能尝试在其上进行投影的任何OOP语言都相去甚远。
那么您的数据类型可以是字符串数组还是单个字符串? 您希望长度函数返回什么? 如果你这样做
bashLength :: BashVar -> Int
bashLength (BashString s) = length s
bashLength (BashArray xs) = length xs
您将获得字符串的长度:
Main> bashLength (BashString "hello")
5
或数组的长度:
Main> bashLength (BashArray ["1","2","3"])
3
因此,这两种情况实际上在含义上有很大不同。 那是你要的吗? 这不是一种列表式的行为。 如果您想进一步研究list数据类型和length函数的实现,请访问 : http : //www.haskell.org/onlinereport/standard-prelude.html
如果只希望您的类型表现得完全像字符串列表,则可以使用类型同义词,并免费获得列表类型的所有功能:
type BashVar = [String]
或者您可以尝试使用递归数据类型,以与定义列表类型相同的方式来模仿列表行为:
data BashVar = BashString String | BashArray [BashVar] deriving (Show)
现在,我将使bashLength仅返回数组的长度-但我不确定这是否是您要表达的内容:
bashLength :: Num a => BashVar -> a
bashLength (BashString s) = 1
bashLength (BashArray xs) = sum (map bashLength xs)
让我们尝试一下:
Main> bashLength(BashArray [])
0
Main> bashLength(BashArray [BashString "b",BashString "c"])
2
不过,如果使用这种方法,则必须将函数命名为“ bashLength”或类似名称,因为“长度”已在列表中定义,并且Haskell中的函数重载通过类型类进行。 至少在Haskell 98中,列表类型是数据类型,而不是类型类,您可以在自己的数据类型“ BashVar”中实现其功能。 为了避免这种限制,如果您想了解更多信息,除了将列表类型包装在自己的数据类型中还有更多技巧: http : //www.haskell.org/haskellwiki/List_instance
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.