Haskell计算列表的元素

时间:2011-12-08 21:03:40

标签: string list haskell printing count

我有这个代码,我试图创建以计算记录数量并打印它们,我似乎无法使它工作我不断得到函数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

此外,有更简单的方法吗?

3 个答案:

答案 0 :(得分:5)

问题:

您已经为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推断出类型! 但它可能不会做你想要的。

答案 1 :(得分:4)

我想我知道发生了什么。

reportReg :: [String]

声明reportReg 字符串列表。但是您希望reportReg成为函数(在->类型中标记),其中采用字符串列表:

reportReg :: [String] -> ???

现在唯一的问题是取代???的内容 - reportReg会返回什么内容?

这就是Haskell与其他语言不同的地方。它返回 I / O操作。它是一个将字符串列表映射到动作的函数 - 即,而不是要返回的值(因此它确实返回值 - 但该值的目的是描述要执行的操作) 。我们写了这种描述操作的值IO ()的类型。所以:

reportReg :: [String] -> IO ()

答案 2 :(得分:0)

其他人已经指出了导致错误的原因,但我会就你提出的另一个问题发表评论:

  

此外,有更简单的方法吗?

是的,计算列表元素的简单方法是使用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打印结果。