0

我有一个由两个别名组成的数据类:Stringand [String],即[Char]and [[Char]]。目前它派生EqShow

data BashVar = BashString String | BashArray [String] deriving (Eq,Show)

为什么它不能派生自[_]或无论如何调用通用列表类型?

我只想能够在类的实例上使用列表函数,特别是length.

4

4 回答 4

8

列表没有类。 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类不允许列表中的任何类型,它固定为字符串列表。因此,即使ListLike存在,您也无法支持它(Foldable出于同样的原因,您也无法派生)。

于 2013-09-13T11:39:47.960 回答
3

两者都是类型类,而同时Eq是数据类型。如果您查看 的类型,则为 ,而为。不同之处在于第一个具有类型类约束,而第二个根本不依赖于类型类约束,仅依赖于数据类型。不幸的是,没有办法使默认值适用于自定义数据类型。Show[](==)Eq a => a -> a -> Boollength[a] -> IntEq a[a]length

最好的办法是定义自己的函数:

bashLength :: BashVar -> Int
bashLength (BashString s) = length s
bashLength (BashArray xs) = length xs
于 2013-09-13T12:52:13.303 回答
1

从您的问题和评论中,您说了如下废话:

  • 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]

很容易发现您正在尝试“跳跃”该语言,而无需花费最少的时间阅读甚至最基本的教程。

至少熟悉“Learn You a Haskell”的“Types and Typeclasses”一章应该可以消除您在这里提出的所有问题。否则根本不可能解释事情,因为该语言及其大多数概念与您可能试图在其上投射的任何 OOP 语言都大不相同。

于 2013-09-13T12:48:37.600 回答
1

那么您的数据类型可以是字符串数组还是单个字符串?你希望你的长度函数返回什么?如果你这样做

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

因此,这两种情况实际上在含义上非常不同。那是你要的吗?这不是一个非常类似于列表的行为。查看列表数据类型和长度函数的实现,如果您想更深入地了解这一点: 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”或类似的名称,因为“length”已经在列表中定义,并且 Haskell 中的函数重载通过类型类工作。列表类型,至少在 Haskell 98 中,是一种数据类型,而不是可以在自己的数据类型“BashVar”中实现其功能的类型类。为了规避这个限制,如果您想阅读更多信息,还有比将列表类型包装在您自己的数据类型中更多的技巧: http ://www.haskell.org/haskellwiki/List_instance

于 2013-09-13T15:11:01.720 回答