Why is there a parse error on this? I insert a list and want to get tuples out. (The top line is correct).
freq :: Eq a => [a] -> [(Int,a)]
freq x:xs = [(x,y)| (x,y) x <- count , y <- rmdups]
There are two syntax errors here — no parenthesis on the pattern, and wrongly placed (x,y) inside the comprehension. It should be:
freq (x : xs) = [(x, y) | x <- count, y <- rmdups]
You have to put parenthesis in your pattern match
freq (x:xs) = {- ... -}
Related
I tried to insert an integer at the correct position into a sorted list of integers.
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x [y:ys] = if x <= y
then [x:y:ys]
else y insert x [ys]
Can anyone tell me what's wrong here and how to fix it? Here are the errors I have encountered:
You have several errors here.
In the argument list, y:ys is already a list, there is no need in wrapping it again like [y:ys], - this has type [[Int]], that is, a list of lists. Note that we still have to put brackets here, to tell Haskell that this is a single function agument: (y:ys).
In your "then" clause, again, x:y:ys is already a list, - don't wrap it into [x:y:ys].
In your "else" clause, y insert x [ys] is function application - Haskell thinks that y is a function that you are applying to arguments insert, x and [ys]. You need operator : here, like y : insert ...
Again, in your "else" clause, you repeat the first error: ys is already a list, don't wrap it into [ys].
So, a fixed solution would be:
insert :: Int -> [Int] -> [Int]
insert x [] = [x]
insert x (y:ys) = if x <= y
then x:y:ys
else y : insert x ys
You are treating y as a function, not an element. You need to use : to construct a new list. Also, for a list, you use [...] or x:xs, not both. [x,y] is syntactic sugar for x:y:[].
insert x [] = x
insert x (y:ys) = if x <= y
then x:y:ys
else y : insert x ys
Another solution, probably not most efficient but still should be good (w/o explicit recursion and pattern matching on list):
insert :: Int -> [Int] -> [Int]
insert x l = let (lower, greater) = span (< x) l in lower ++ x : greater
And this solution is also lazy as you can see:
λ: insert 3 [1,2,4]
[1,2,3,4]
λ: take 10 $ insert 5 $ repeat 1
[1,1,1,1,1,1,1,1,1,1]
I think I need something like a fold or maybe a foldt but the examples I've seen, seem to only compress the list into a simple scalar value.
What I need would need to remember and re-use values from previous lines in the list (essentially a "group by" operation)
If my input data looks like:
[["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
What is the correct approach to end up with something like:
[["order1",["item1","item2","item3"]],["order2",["item4"]]
ie data Order = Order { id :: Text, items :: [OrderItem]}
What if I wanted a slightly different structure?
[("order1",["item1","item2","item3"]),("order",["item4"])]
ie data OrderTuple = OrderTuple { order :: Order, items :: [OrderItem]}
What if I also wanted to keep a running total of some numeric value from the OrderItem?
edit: Here's the code I'm trying to get working based on Frerich's answer
--testGroupBy :: [[String]] -> [[String]]
testGroupBy :: [[String]] -> [(String, [String])]
testGroupBy z =
--groupBy (\(x:xs) (y:ys) -> x == y || null y) z
groupBy testFunc z
testFunc :: [String] -> [String] -> Bool
testFunc (x:xs) (y:ys) = x == y || null y
Pattern matching is useful here
groupData = foldl acc []
where acc ((r, rs):rss) ("":xs) = (r, rs ++ xs): rss
acc rss (x:xs) = (x, xs): rss
acc _ _ = error "Bad input data"
resultant groups are in reverse order, use reverse if you need.
What if I wanted a slightly different structure?
Simply transform one into other, you can do inside groupData or as separated function.
If you admit initial groups without fst element
groupData = foldr acc []
where acc (x:xs) [] = [(x, xs)]
acc ("":xs) (("", rs):rss) = ("", rs ++ xs): rss
acc (x:xs) (("", rs):rss) = (x, rs ++ xs): rss
acc (x:xs) rss = (x, xs): rss
then
let xs = [["", "item8"],["", "item9"],["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
print $ groupData xs
is
[("",["item9","item8"])
,("order1",["item3","item2","item1"])
,("order2",["item4"])]
Instead of looking for a fold-based solution, I'd first try to see whether you can define a function as a composition of higher-level functions (such as map). Let me fire up a ghci session and play abit:
λ: let x = [["order1", "item1"],["", "item2"],["","item3"],["order2","item4"]]
Your "group by" operation actually has an existing name: Data.List.groupBy -- this almost gets us what we need:
λ: import Data.List
λ: let x' = groupBy (\(x:xs) (y:ys) -> x == y || null y) x
λ: x'
[[["order1","item1"],["","item2"],["","item3"]],[["order2","item4"]]]
This groupBy application puts all elements in x into one group (i.e. list) whose first element is equal, or if the second element is empty. This can then get massaged into your desired format (in this case, the second one you proposed with a map):
λ: let x'' = map (\x -> (head (head x), map (!! 1) x)) x'
λ: x''
[("order1",["item1","item2","item3"]),("order2",["item4"])]
Putting it all together:
groupData :: [[String]] -> [(String, [String])]
groupData = map (\x -> (head (head x), map (!! 1) x))
. groupBy (\(x:xs) (y:ys) -> x == y || y == "")
I suppose that with this, building a proper data structure (i.e. something more typesafe than nested lists) should be straightforward.
tuplesList = [('a','m'), ('b', 'n'), ('c', 'o'), etc]
How do I search this list for a value by first looking at first elements and returning the second if found, but if not found then look at the second elements and return the first element if found. e.g. searching for 'a' would return 'm' and searching for 'n' returns 'b'?
I tried this:
lookup :: Char -> [(Char,Char)] -> Char
lookup x zs = (head [b | (a,b) <- zs, (a==x)])
lookup x zs = (head [a | (a,b) <- zs, (b==x)])
but I don't know how to say if the the 2nd line doesn't find a match then do the 3rd line.
Any help is appreciated.
Haskell already has its own lookup function which you should probably make use of:
lookup' :: Char -> [(Char,Char)] -> Char
lookup' x zs = case (search1, search2) of
(Just y, _) -> y
(Nothing, Just y) -> y
(Nothing, Nothing) -> error "What am I supposed to do here I DON'T KNOW"
where search1 = lookup x zs
search2 = lookup x [(b,a) | (a,b) <- zs]
A nice way to expand your partial solution is to just concatenate the two lists of candidates together, as in:
lookup x zs = head ([ b | (a,b) <- zs, a == x ] ++ [ a | (a,b) <- zs, b == x ])
Do you see why this works?
It's not maximally efficient, because if there's no match on the first component of the tuples it will go through zs twice - if zs is very large this holds on to zs longer than necessary.
In order to improve that I would do something like this (but only if it's very important!):
lookup x zs = goNoSecondBestYet zs where
goNoSecondBestYet [] = error "Nothing found"
goNoSecondBestYet ((a,b):abs)
| a == x = b -- we're done!
| b == x = goSecondBestFound b abs -- keep track of the newly found second best candidate
| otherwise = goNoSecondBestYet abs -- just go on
goSecondBestFound y [] = y
goSecondBestFound y ((a,b):abs)
| a == x = b -- we're done, never mind the second best
| otherwise = goSecondBestFound y abs -- keep going, we already have a second best
This is pretty complex already (try to generalise this to use 4-tuples to see what I mean!) and I would normally use Maybe for this; but it does go through the list only once.
You should consider that a lookup may fail. The natural thing to do here is to return a list of results:
lookup :: Eq a => a -> (a,a) -> [a]
lookup item xs = [ if a==c then b else a | (a,b) <- xs, a == c || b == c ]
I have this function which removes occurrences of a given element within the list of lists.
remove :: Eq a => a -> [[a]] -> [[a]]
remove y [] = error "Can't remove an element from an empty list"
remove y xs = map (filter(/=y)) xs
How would I be able to do the same using List comprehension
Thank you
For each l in xs, add filter (/= xs) l to the resulting list:
remove y xs = [filter (/= y) l | l <- xs]
or, removing filter by nesting comprehensions.
For each xs in xss and for each x in xs, keep x only if it's different from y:
remove y xss = [ [x| x <- xs, x /= y] | xs <- xss]
It's OK if you're just practicing , but your version with map is way better :)
I guess something along the lines of:
remove y ls = [f|l <- ls, let f = filter (/= y) l]
should be fine.
It basicly states that for every binding l you can make in the list ls, add the filtered list f to the resulting list.
something like
getFirstError :: [Either a b] -> a
getFirstError (x:y:...:Left w:z) = w
wrt Haskell but it might be interesting to know how other languages with pattern matching accomplish this.
You can, despite the other answers, do this using view patterns extension in GHC:
getFirstError ((msum . map test) -> Just x) = x
where test (Left x) = Just x
test (Right x) = Nothing
Alternatively using pattern guards:
getFirstError (xs) | Just x <- (msum $ map test xs) = x
where test (Left x) = Just x
test (Right) x = Nothing
No, but you can use a list comprehension
getFirstError xs = head [ x | Left x <- xs ]
Note that head will fail if there are no errors.
No, there's not. However, you can easiliy write the function using recursion:
getFirstError [] = error "getFirstError: empty list or no error"
getFirstError (Left x : xs) = x
getFirstError (_ : xs) = getFirstError xs