【问题标题】:Haskell counting elements of a listHaskell计算列表的元素
【发布时间】:2011-12-08 21:03:40
【问题描述】:

我尝试创建这段代码来计算记录数量并打印它们,但我似乎无法让它工作我经常收到关于函数 reportReg 应用于一个参数但其类型 [String] 没有的错误。

report :: [[String]] -> String -> [String]
report (x:xs) typ = do
                    case typ of
                        "registrations" -> reportReg (map head xs)
                        "completions" -> reportReg (map head xs)

reportReg :: [String]
reportReg [x] = do
                    print x
                    print 1
reportReg (x:xs) = do 
                    let count = instances x (x:xs)
                    print x
                    print count
                    let newlist = filter (==x) (x:xs)
                    reportReg newlist

instances::String->[String]->Int
instances x [] = 0
instances x (y:ys)
    | x==y = 1+(instances x ys)
    | otherwise = instances x ys

另外,有没有更简单的方法来做到这一点?

【问题讨论】:

  • 看起来您正在输入“字符串”。否则很难看出你在做什么。也许更具描述性。

标签: string list haskell printing count


【解决方案1】:

问题:

你给reportReg 一个字符串列表类型:

reportReg :: [String]

这只是一个值,或 0 个参数的函数。这解释了您遇到的错误 - 试图给它一个参数,但它没有。

解决方案:

  • 看起来你想在reportReg做IO动作,所以你应该改变类型注解:

    reportReg :: [String] -> IO ()
    

-- --

  • 编写不带类型注释的函数,让 Haskell 为您推断,然后复制该注释

问题:

report 的返回类型错误。它必须与reportReg 相同。但是reportReg :: String -> IO (),而report :: [[String]] -> String -> [String]

几种可能的解决方案:

  • reportReg中移除IO动作,使其类型为[String] -> [String]。我强烈建议这样做——任何语言的 IO 总是很痛苦,但 Haskell 很酷的一点是它让你感到痛苦——从而激励你尽可能避免 IO!
  • report 的类型更改为[[String]] -> String -> IO ()

懒人的解决办法:

我将您的代码复制到一个文本文件中,删除了注释(不做其他更改),并将其加载到ghci

Prelude> :load typef.hs 
[1 of 1] Compiling Main             ( typef.hs, interpreted )
Ok, modules loaded: Main.
*Main> :t report
report :: (Eq a, Show a) => [[a]] -> [Char] -> IO ()
*Main> :t reportReg 
reportReg :: (Eq a, Show a) => [a] -> IO ()
*Main> :t instances 
instances :: (Num t, Eq a) => a -> [a] -> t

它有效——Haskell 推断类型! 但它可能做不到你想要的。

【讨论】:

  • 我试过这个,它产生了另一个错误,说它期待类型 IO () 而不是 [String]
  • @user1009731 -- 那是因为report -- 你是说report 将返回一个[String],但Haskell 知道它必须返回一个IO ()(因为这就是reportReg 返回)。很快就会更新。
  • 好的,谢谢 :) 我现在看到了问题。计算现在有效,但计算不正确。
【解决方案2】:

我想我明白发生了什么。

reportReg :: [String]

声明reportReg 一个字符串列表。但是您希望reportReg 成为一个函数(在类型中由-> 标记),它接受一个字符串列表:

reportReg :: [String] -> ???

现在唯一的问题是用什么代替 ??? -- reportReg 返回什么?

这就是 Haskell 与其他所有语言的不同之处。它返回一个I/O 动作。它是一个将字符串列表映射到操作的函数——即,do 的某事而不是返回的值(因此它确实返回值——但该值的目的是描述要做什么) .我们写出这种动作描述值的类型IO ()。所以:

reportReg :: [String] -> IO ()

【讨论】:

  • 我以前试过这个,但是它产生了 IO 错误,说无法将预期类型 [String] 与实际类型 IO () 匹配
【解决方案3】:

其他人已经指出了您错误的原因,但我将对您提出的其他问题发表评论:

另外,有没有更简单的方法来做到这一点?

是的,计算列表元素的简单方法是使用length 函数。如果需要统计有多少元素满足一个谓词,可以取过滤结果的长度。我不完全理解您的代码(例如,typ 参数在做什么?),但这里有一个示例(可能不完全一样):

reportReg :: [a] -> IO ()
reportReg [] = do return ()
reportReg xs = do print (head x)
                  print (count x xs)
                  reportReg (tail xs)

count :: a -> [a] -> Integer
count x xs = length (filter (==x) xs)

我建议的主要建议是从 do 块中提取尽可能多的代码(我上面的代码在这方面仍然可以使用改进)。尝试用纯代码完全解决您的问题,并仅使用 IO monad 打印结果。

【讨论】:

  • 我试图计算并打印出数组中每个唯一出现的字符串,例如 [a,a,a,b,a,b,b,c,c] -> "a " 4 "b" 3 "c" 2
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-01-14
  • 2013-12-02
  • 1970-01-01
  • 2011-08-04
相关资源
最近更新 更多