Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Foldl operation on a list of lists in Haskell

Tags:

haskell

I have a list of lists like for example

[[1,2,3,5],[24,6,8,2],[2,4,5,6,8]]

The goal is to obtain the list of elements common in all the lists. My approach was to create a function that outputs the common elements in two lists

 common :: (Foldable t, Eq a) => [a] -> t a -> [a]
 common list1 list2 = [x | x<-list1, elem x list2]

and do the operation recursively on all the elements of [[a]] using a fold operation

 main :: IO ()
 main = do

    --- get the number of lists
    q <- readLn :: IO Int

    --- get the lists and store in a list of lists
    list_of_lists <- map (map (read::String->Int ) . words) <$> replicateM q getLine :: IO [[Int]]

    --- process and print the output
    putStrLn $ show $ foldl (common) list_of_lists

Unfortunately, this doesn't compile and gives an error

• Ambiguous type variable ‘t1’ arising from a use of ‘common’
      prevents the constraint ‘(Foldable t1)’ from being solved.
      Probable fix: use a type annotation to specify what ‘t1’ should be.
      These potential instances exist:
        instance Foldable (Either a) -- Defined in ‘Data.Foldable’
        instance Foldable Maybe -- Defined in ‘Data.Foldable’
        instance Foldable ((,) a) -- Defined in ‘Data.Foldable’
        ...plus one other
        ...plus 26 instances involving out-of-scope types
        (use -fprint-potential-instances to see them all)
    • In the first argument of ‘foldl’, namely ‘(common)’
      In the second argument of ‘($)’, namely ‘foldl (common) list_of_lists’
      In the second argument of ‘($)’, namely
        ‘show $ foldl (common) list_of_lists’

I can understand the probable fix lies in how the function common is defined, but couldn't seem to get it, as I am relatively new to Haskell.

like image 528
Anthony M Benedict Avatar asked Nov 19 '25 10:11

Anthony M Benedict


1 Answers

You should make use of foldl1, or provide the initial value for the accumulator. foldl :: Foldable t => (b -> a -> b) -> b -> t a -> b expects an initial value as accumulator of type b. With foldl1 :: Foldable t => (a -> a -> a) -> t a -> a, it takes the first element as initial accumulator:

import Control.Monad(replicateM)

main :: IO ()
main = do
    q <- readLn :: IO Int
    list_of_lists <- replicateM q (map read . words <$> getLine) :: IO [[Int]]
    print (foldl1 common list_of_lists)

This gives us:

Prelude Control.Monad> main
3
1 2 3 5
24 6 8 2
2 4 5 6 8
[2]

The above function will error if the list of items is empty. So here q should, like @JosephSible says, be strictly greater than zero.

like image 160
Willem Van Onsem Avatar answered Nov 22 '25 02:11

Willem Van Onsem