简体   繁体   中英

Haskell counting elements of a list

I have this code that I tried to create to count amount of records and print them, I cant seem to get it working I constantly get errors about a function reportReg being applied to one argument but its type [String] having none.

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

Also, is there an easier way to do this?

Problem:

You've given reportReg a type of list of string:

reportReg :: [String]

This is simply a value, or a function of 0 arguments. That explains the error you were getting -- trying to give it an argument, but it takes none.

Solutions:

  • It looks like you want to do IO actions in reportReg , so you should change the type annotation:

     reportReg :: [String] -> IO () 

-- or --

  • write the function without a type annotation, let Haskell infer it for you, and then copy down that annotation

Problem:

report 's return type is wrong. It has to be the same as that of reportReg . But reportReg :: String -> IO () , whereas report :: [[String]] -> String -> [String] !

A couple possible solutions:

  • remove IO actions from reportReg , so that its type is [String] -> [String] . I'd strongly suggest doing this -- IO in any language is always a pain, but the cool thing about Haskell is that it makes you feel the pain -- thereby giving you an incentive to avoid IO as much as possible!
  • change type of report to [[String]] -> String -> IO ()

Lazy man's solution:

I copied your code into a text file, removed the annotations (making no other changes), and loaded it into 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

It works -- Haskell infers the types! But it may not do what you want.

I think I see what is going on.

reportReg :: [String]

declares that reportReg is a list of strings. But you want reportReg to be a function (marked in the type by -> ) which takes a list of strings:

reportReg :: [String] -> ???

Now the only question is what goes in place of the ??? -- what does reportReg return?

This is where Haskell differs from every other language. It returns an I/O action . It is a function which maps lists of strings to actions -- namely, something to do rather than a value to return (so it does return value -- but that value's purpose is to describe what to do). We write the type of such action-describing values IO () . So:

reportReg :: [String] -> IO ()

Other folks have pointed out the cause for your error, but I will comment on the other issue you've raised:

Also, is there an easier way to do this?

Yeah, the simple way to count the elements of a list is to use the length function. If you need to count how many elements satisfy a predicate, you can take the length of the result of filtering. I don't completely understand your code (eg, what's that typ argument doing?), but here's an example (that probably doesn't do exactly the same):

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)

The main piece of advice I would suggest it to pull out as much code as possible from the do blocks (my code above still could use improvement in that regard). Try to solve your problem completely in terms of pure code, and use the IO monad only to print the result.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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