目前使用Haskell处理一个函数,该函数在参数中获取String并返回列表(Char,Int)该函数适用于多种类型,并在名为的函数中使用字即可。
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)]
给我这个错误
ERROR "file.hs":31 - Type error in generator
*** Term : head xs
*** Type : Char
*** Does not match : [a]
我做错了什么?如何使这个代码正确运行,类型?
答案 0 :(得分:3)
问题是您说xs
的类型为String
,因此head xs
的类型为Char
,然后您尝试迭代一个Char
,这是无法做到的。仅当a <- b
是列表时,b
语法才有效。您遇到同样的问题,因为y <- occur x xs
正在尝试迭代单个Int
,而不是Int
列表。您的类型签名也存在问题,元组中的第一个类型应为Char
,而不是String
。您可以使用以下方法修复它:
word :: String -> [(Char, Int)]
word xs = [(x, occur x xs) | x <- xs]
这里我们遍历整个字符串xs
,对于x
中的每个字符xs
,我们计算occur x xs
。
我实际上建议使用比Eq
更强的约束。如果您将word
(我已重命名为occurrences
)并将其约束为Ord
,则可以使用group
和sort
,这样您就可以不要为每个字符重复遍历列表,并避免O(n^2)
复杂性。您还可以非常简化定义:
import Control.Arrow
import Data.List
occurrences :: Ord a => [a] -> [(a, Int)]
occurrences = map (head &&& length) . group . sort
这样做首先对列表进行排序,然后按相同的元素进行分组。所以"Hello, world"
变成了
> sort "Hello, world"
" ,Hdellloorw"
> group $ sort "Hello, world"
[" ", ",", "H", "d", "e", "lll", "oo", "r", "w"]
然后我们使用箭头操作符&&&
,它接受两个函数,对两个函数应用单个输入,然后将结果作为元组返回。所以head &&& length
与说
\x -> (head x, length x)
我们将其映射到已排序的分组列表:
> map (head &&& length) $ group $ sort "Hello, world"
[(' ',1),(',',1),('H',1),('d',1),('e',1),('l',3),('o',2),('r',1),('w',1)]
这消除了重复,您不必一遍又一遍地扫描列表中的元素数量,并且可以在pointfree样式中以单行定义,这很好。但是,它不会保留顺序。如果您需要保留订单,我会使用sortBy
和来自comparing
的便捷函数Data.Ord
(但我们会丢失一个不错的点免费表单):
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
你几乎可以用简单的英语来读这个。这通过比较xs
中元组的第一个元素的occurrences xs
中的索引进行排序。即使elemIndex
返回Maybe Int
类型的值,我们仍然可以直接比较它们(Nothing
是“小于”任何Just
值)。它只是查找原始字符串中每个字母的第一个索引,并按该索引排序。那样
> occurrences' "Hello, world"
返回
[('H',1),('e',1),('l',3),('o',2),(',',1),(' ',1),('w',1),('r',1),('d',1)]
包含原始顺序中的所有字母,直到重复。