Warning: file_get_contents(/data/phpspider/zhask/data//catemap/6/haskell/9.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Generics 从数据类中的列表导出长度函数_Generics_Haskell - Fatal编程技术网

Generics 从数据类中的列表导出长度函数

Generics 从数据类中的列表导出长度函数,generics,haskell,Generics,Haskell,我有一个由两个别名组成的数据类:String和[String],即[Char]和[[Char]]。目前它派生出Eq和Show: data BashVar = BashString String | BashArray [String] deriving (Eq,Show) 为什么它不能同时从[\u]派生,或者以调用泛型列表类型的方式派生 我只想能够在类的实例上使用list函数,特别是length没有用于list的类长度仅定义为: length :: [a] -> Int 不是(我想你想

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

data BashVar = BashString String | BashArray [String] deriving (Eq,Show)
为什么它不能同时从
[\u]
派生,或者以调用泛型列表类型的方式派生


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

没有用于list的类<代码>长度仅定义为:

length :: [a] -> Int
不是(我想你想象的那样):

最接近列表的类可能是可折叠的:但这并没有定义长度,只是不同的折叠


除此之外,如果有一个list类,它可能仍然允许内部类型发生变化,如我上面的示例所示。您的
BashVar
类不允许列表中有任何类型,它固定为字符串列表。因此,即使存在
ListLike
,您也无法支持它(出于同样的原因,您也无法从您的问题和评论中派生出
Foldable

,在这些问题和评论中,您会说下面这样的废话:

  • 我有一个数据类
  • BashVar是[a]
很容易发现你试图“跳转”语言,而不用花最少的时间阅读最基本的教程


至少让你自己熟悉“学会哈斯克尔”这句话应该可以抹掉你在这里提出的所有问题。否则就不可能解释事情,因为该语言及其大多数概念与您可能尝试在其上投影的任何OOP语言都有太大的不同。

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

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

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函数的实现:

如果您只希望类型的行为与字符串列表完全相同,则可以使用类型同义词并免费获取列表类型的所有函数:

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”中实现其函数。 为了避免此限制,如果您想阅读更多内容,除了在自己的数据类型中包装列表类型外,还有更多技巧:

我不太理解第二部分:当然,BashVar是
[a]
的一个实例,其中
a
可以是
Char
String
(因为
String
[Char]
的别名)。但是第一部分的意思是除了隐藏内置代码和导入/编写新代码之外,没有办法让
length
使用BashVar吗?@flyingsheep:no.
BashVar
本身只是一种数据类型,而不是类似
[a]
的实例。它确实包含这种类型的值,但这是完全不同的。在OO语言中,“从某个类继承”和“作为该类对象的组合”可能看起来很相似,但Haskell对这两个概念进行了很强的区分。请注意,长度只能用Foldable:
length=getSum来定义。foldMap Sum
很好,但是通过检查组合中的每个类是否都是Eq和Show的实现,然后启用在组合类上使用“Eq”或“Show”的函数,派生(Eq,Show)不起作用吗?这就是我现在正在做的,但是它看起来非常愚蠢:我有一个肯定是列表的东西,但是为了调用它的列表函数,我必须在应用泛型列表函数之前检查它是哪种类型的列表。这就像在给他们水果沙拉之前先问他们是否想要苹果或桔子,沙拉中包含这两种水果。@flyingsheep这是使用代数数据类型的陷阱之一。您定义了一个类型,该类型可以是字符串或字符串列表,但仍然希望在列表中使用列表函数,在字符串中使用字符串函数。虽然这一层非常有用,但有时它意味着你的函数没有那么“直观”的意义。“字符串函数”在这里没有意义:“长度”是一个列表函数,因为在haskell中,
string
可以与
[Char]
互换。这意味着我们在每个分支中执行完全相同的机器代码。s是一个列表,xs是一个列表:相同的东西。这就是我的问题:哈斯克尔强迫我做一个完全不必要的决定
Main> bashLength(BashArray [])
0
Main> bashLength(BashArray [BashString "b",BashString "c"])
2