简体   繁体   English

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

[英]Deriving length function from List in data class

I have a data class that consists of two aliases: String and [String] , ie [Char] and [[Char]] . 我有一个包含两个别名的数据类: String[String] ,即[Char][[Char]] Currently it derives Eq and Show : 目前它派生EqShow

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

Why can't it derive also from [_] or however the generic list type is called? 为什么它不能也从[_]派生出来,或者为什么却调用了通用列表类型?

I just want to be able to use list functions on instances of the class, specifically length . 我只希望能够在类的实例上使用列表函数,特别是length

There is no class for lists. 列表没有类别。 length is defined simply as: length简单定义为:

length :: [a] -> Int

Not (as I think you imagine): 不(正如我想像的那样):

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

The closest class to list is probably Foldable : http://hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html But that doesn't define length , just various folds. 列表中最接近的类可能是Foldablehttp : //hackage.haskell.org/packages/archive/base/latest/doc/html/Data-Foldable.html但这并没有定义length ,只是各种折叠。

Besides which, if there was a list class, it would probably still allow the inner type to vary, as in my example above. 除此之外,如果有一个列表类,它可能仍将允许内部类型变化,如上面的示例所示。 Your BashVar class doesn't allow any type in the lists, it's fixed to lists of String. 您的BashVar类不允许列表中使用任何类型,而是固定为String列表。 So even if ListLike existed, you couldn't support it (and you can't derive Foldable for the same reason). 因此,即使存在ListLike ,您也无法支持它(并且出于相同的原因也无法派生Foldable )。

Both Eq and Show are typeclasses , while [] is a data type . EqShow都是类型类 ,而[]数据类型 If you look at the type of (==) , it's Eq a => a -> a -> Bool , while length is [a] -> Int . 如果查看(==)的类型,则为Eq a => a -> a -> Bool ,而length[a] -> Int The difference is that the first one has a typeclass constraint Eq a , and the second one doesn't depend on a typeclass constraint at all, merely on the data type [a] . 不同之处在于,第一个具有类型分类约束Eq a ,而第二个则完全不依赖于类型分类约束,仅依赖于数据类型[a] Unfortunately, there's no way to make the default length work with custom data types. 不幸的是,无法使默认length与自定义数据类型一起使用。

Your best bet is to defined your own functions: 最好的选择是定义自己的功能:

bashLength :: BashVar -> Int
bashLength (BashString s) = length s
bashLength (BashArray xs) = length xs

From your question and comments, where you say a nonsense like the following: 从您的问题和评论中,您在说些废话,如下所示:

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

it's easy to detect that you're trying to "jump" the language without spending the least amount of time at reading even the most basic tutorials. 可以很容易地发现您正在尝试“跳动”该语言,而无需花费最少的时间来阅读最基本的教程。

Getting yourself acquainted at least with the "Types and Typeclasses" chapter of "Learn You a Haskell" should erase all the questions you've asked here. 至少让您熟悉“了解Haskell”的“类型和类型分类”一章 ,才能消除您在此处提出的所有问题。 It would be merely impossible to explain things otherwise, because the language and most of its concepts are way too different from any OOP language you may be trying to project on it. 否则就不可能对其他事物进行解释,因为该语言及其大多数概念与您可能尝试在其上进行投影的任何OOP语言都相去甚远。

So your datatype can be either an array of strings or a single string? 那么您的数据类型可以是字符串数组还是单个字符串? What do you want your length function to return? 您希望长度函数返回什么? If you do 如果你这样做

bashLength :: BashVar -> Int
bashLength (BashString s) = length s
bashLength (BashArray xs) = length xs

you get either the length of the string: 您将获得字符串的长度:

Main> bashLength (BashString "hello")
5

or the length of the array: 或数组的长度:

Main> bashLength (BashArray ["1","2","3"])
3

So both cases are in fact very different in meaning. 因此,这两种情况实际上在含义上有很大不同。 Is that what you want? 那是你要的吗? It is not a very list-like behaviour. 这不是一种列表式的行为。 Look at the implementation of the list datatype and the length function, if you want to dive more into this: http://www.haskell.org/onlinereport/standard-prelude.html 如果您想进一步研究list数据类型和length函数的实现,请访问http : //www.haskell.org/onlinereport/standard-prelude.html

If you just want your type to behave exactly like a list of strings, you could use a type synonym and get all the functions of the list type for free: 如果只希望您的类型表现得完全像字符串列表,则可以使用类型同义词,并免费获得列表类型的所有功能:

type BashVar = [String]

Or you could try a recursive datatype, in the same way the list type is defined, to mimick the list behaviour: 或者您可以尝试使用递归数据类型,以与定义列表类型相同的方式来模仿列表行为:

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

Now, I would make bashLength just return the length of the array - but I'm not sure if that's what you want to express: 现在,我将使bashLength仅返回数组的长度-但我不确定这是否是您要表达的内容:

bashLength :: Num a => BashVar -> a
bashLength (BashString s) = 1
bashLength (BashArray xs) = sum (map bashLength xs)

Let's try it: 让我们尝试一下:

Main> bashLength(BashArray [])
0
Main> bashLength(BashArray [BashString "b",BashString "c"])
2

Still, if you use this approach, you have to name your function "bashLength" or something like that, because "length" is already defined on lists, and overloading of functions in Haskell works via type classes. 不过,如果使用这种方法,则必须将函数命名为“ bashLength”或类似名称,因为“长度”已在列表中定义,并且Haskell中的函数重载通过类型类进行。 The list type, at least in in Haskell 98, is a datatype, not a type class whose functions you could implement in your own datataype "BashVar". 至少在Haskell 98中,列表类型是数据类型,而不是类型类,您可以在自己的数据类型“ BashVar”中实现其功能。 To circumvent this limitation, there are even more tricks than wrapping the list type in your own datatype, in case you want to read more: http://www.haskell.org/haskellwiki/List_instance 为了避免这种限制,如果您想了解更多信息,除了将列表类型包装在自己的数据类型中还有更多技巧: http : //www.haskell.org/haskellwiki/List_instance

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM