从数据类中的List派生长度函数

时间:2013-09-13 11:23:06

标签: generics haskell

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

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

为什么它也不能从[_]派生出来,或者是否会调用泛型列表类型?

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

4 个答案:

答案 0 :(得分:8)

列表没有课程。 length简单定义为:

length :: [a] -> Int

不(我认为你想象):

class ListLike l where
  length :: l a -> Int

最接近列出的类可能是Foldablehttp://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html但是这并没有定义length,只是不同的折叠。

除此之外,如果有一个列表类,它可能仍然允许内部类型变化,如上例所示。您的BashVar类不允许列表中的任何类型,它已修复为String列表。因此,即使存在ListLike,也无法支持它(并且出于同样的原因,您无法导出Foldable。)

答案 1 :(得分:3)

EqShow都是类型,而[]数据类型。如果您查看(==)的类型,它是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

答案 2 :(得分: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]

很容易发现你试图“跳”语言而不花费最少的时间阅读最基本的教程。

让自己至少熟悉“了解你的哈斯克尔”的"Types and Typeclasses" chapter应该删除你在这里提出的所有问题。否则就不可能解释其他事情,因为语言及其大部分概念与您尝试在其上投射的任何OOP语言有太大的不同。

答案 3 :(得分: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

因此,两种情况的意义都非常不同。 那是你要的吗?它不是一个非常类似列表的行为。查看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”或类似的东西,因为“length”已在列表中定义,而Haskell中的函数重载通过类型类工作。列表类型,至少在Haskell 98中,是一种数据类型,而不是类型类,其功能可以在您自己的datataype“BashVar”中实现。 为了避免这种限制,除了在您自己的数据类型中包装列表类型之外,还有更多技巧,以防您想要阅读更多内容: http://www.haskell.org/haskellwiki/List_instance