简体   繁体   English

在生成器中输入错误,使用元组生成haskell列表

[英]Type error in generator , haskell list using tuple

Currently working with Haskell on a function that takes a String in parameters and return a list of (Char, Int) The function occur works with multiple type and is used in the function called word . 当前与Haskell一起使用一个函数,该函数接受参数中的String并返回(Char,Int)列表。该函数的出现适用于多种类型,并在名为word的函数中使用。

occur::Eq a=>a->[a]->Int
occur n [] = 0
occur n (x:xs) = if n == x
              then 1 + occur n xs
              else occur n xs

word::String->[(String,Int)]
word xs = [(x,y) | x<-head xs, y<-(occur x xs)]

Get me this error 让我知道这个错误

ERROR "file.hs":31 - Type error in generator
*** Term           : head xs
*** Type           : Char
*** Does not match : [a]

What am I doing wrong ? 我究竟做错了什么 ? How can I make this code run properly , type-wise ? 如何使此代码正确运行(按类型)?

The problem is you say that xs has type String , so head xs has type Char , and then you try to iterate over a single Char , which can't be done. 问题是您说xs类型为String ,所以head xs类型为Char ,然后尝试对单个Char进行迭代,这是无法完成的。 The a <- b syntax only works when b is a list. a <- b语法仅在b是列表时有效。 You have the same problem in that y <- occur x xs is trying to iterate over a single Int , not a list of Int . 您有相同的问题,因为y <- occur x xs试图对单个Int而不是Int列表进行迭代。 You also had a problem in your type signature, the first type in the tuple should be Char , not String . 您的类型签名也有问题,元组中的第一个类型应该是Char ,而不是String You can fix it with: 您可以使用以下方法修复它:

word :: String -> [(Char, Int)]
word xs = [(x, occur x xs) | x <- xs]

Here we loop over the entire string xs , and for each character x in xs we compute occur x xs . 在这里,我们遍历整个字符串xs ,并为每个字符xxs我们计算occur x xs


I would actually recommend using a slightly stronger constraint than just Eq . 我实际上建议使用比Eq稍微强一点的约束。 If you generalize word (that I've renamed to occurrences ) and constrain it with Ord , you can use group and sort , which allow you to keep from iterating over the list repeatedly for each character and avoid the O(n^2) complexity. 如果将word概括(我已将其重命名为occurrences )并使用Ord对其进行约束,则可以使用groupsort ,这样可以避免对每个字符重复遍历列表并避免O(n^2)复杂性。 You can also simplify the definition pretty significantly: 您还可以显着简化定义:

import Control.Arrow
import Data.List

occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort

What this does is first sort your list, then group by identical elements. 这是首先对列表进行排序,然后按相同的元素进行分组。 So "Hello, world" turns into 所以"Hello, world"变成了

> sort "Hello, world"
" ,Hdellloorw"
> group $ sort "Hello, world"
[" ", ",", "H", "d", "e", "lll", "oo", "r", "w"]

Then we use the arrow operator &&& which takes two functions, applies a single input to both, then return the results as a tuple. 然后,我们使用带有两个函数的箭头运算符&&& ,对两个函数都应用单个输入,然后将结果作为元组返回。 So head &&& length is the same as saying 所以head &&& length等于说

\x -> (head x, length x)

and we map this over our sorted, grouped list: 然后将其映射到已排序的分组列表中:

> map (head &&& length) $ group $ sort "Hello, world"
[(' ',1),(',',1),('H',1),('d',1),('e',1),('l',3),('o',2),('r',1),('w',1)]

This eliminates repeats, you aren't having to scan the list over and over counting the number of elements, and it can be defined in a single line in the pointfree style, which is nice. 这消除了重复,您不必重复遍历列表的元素数量,并且可以用无点样式在一行中定义它,这很好。 However, it does not preserve order. 但是,它不保留顺序。 If you need to preserve order, I would then use sortBy and the handy function comparing from Data.Ord (but we lose a nice point free form): 如果您需要保留顺序,那么我将使用sortBy和与Data.Ord comparing的便捷函数(但是我们失去了一种不错的自由点形式):

import Control.Arrow
import Data.List
import Data.Ord (comparing)

occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort

occurrences' :: Ord a => [a] -> [(a, Int)]
occurrences' xs = sortBy (comparing ((`elemIndex` xs) . fst)) $ occurrences xs

You can almost read this as plain English. 您几乎可以用通俗的英语阅读。 This sorts by comparing the index in xs of the first element of the tuples in occurrences xs . 通过比较occurrences xs组第一个元素的xs索引进行排序。 Even though elemIndex returns a value of type Maybe Int , we can still compare those directly ( Nothing is "less than" any Just value). 即使elemIndex返回的类型Maybe Int ,我们仍然可以直接比较它们( Nothing “小于”任何Just值)。 It simply looks up the first index of each letter in the original string and sorts by that index. 它只是查找原始字符串中每个字母的第一个索引,并按该索引排序。 That way 那样

> occurrences' "Hello, world"

returns 退货

[('H',1),('e',1),('l',3),('o',2),(',',1),(' ',1),('w',1),('r',1),('d',1)]

with all the letters in the original order, up to repetition. 所有字母均按原始顺序排列,直到重复为止。

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

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