I'm extracting some data from a text document organized like this:
- "day 1"
- "Person 1"
- "Bill 1"
- "Person 2"
- "Bill 2"
I can read this into a list of tuples that looks like this:
[(0,["day 1"]),(1,["Person 1"]),(2,["Bill 1"]),(1,["Person 2"]),(2,["Bill 2"])]
Where the first item of each tuple indicates the heading level, and the second item the information associated with each heading.
My question is, how can I get a list of items that looks like this:
[["day 1","Person 1","Bill 1"],["day 1","Person 2","Bill 2"]]
I.e. one list per deepest nested item, containing all the information from the headings above it.
The closest I've gotten is this:
f [] = []
f (x:xs) = row:f rest where
leaves = takeWhile (\i -> fst i > fst x) xs
rest = dropWhile (\i -> fst i > fst x) xs
row = concat $ map (\i -> (snd x):[snd i]) leaves
Which gives me this:
[[["day 1"],["Intro 1"],["day 1"],["Bill 1"],["day 1"],["Intro 2"],["day 1"],["Bill 2"]]]
I'd like the solution to work for any number of levels.
P.s. I'm new to Haskell. I have a sense that I could/should use a tree to store the data, but I can't wrap my head around it. I also could not think of a better title.
Trees
You were right that you should probably use a tree to store the data. I'll copy how Data.Tree does it:
data Tree a = Node a (Forest a) deriving (Show)
type Forest a = [Tree a]
Building the Tree
Now we want to take your weakly typed list of tuples and convert it to a (slightly) stronger Tree of Strings. Any time you need to convert a weakly typed value and validate it before converting to a stronger type, you use a Parser:
type YourData = [(Int, [String])]
type Parser a = YourData -> Maybe (a, YourData)
The YourData type synonym represents the weak type that you are parsing. The a type variable is the value you are retrieving from the parse. Our Parser type returns a Maybe because the Parser might fail. To see why, the following input does not correspond to a valid Tree, since it is missing level 1 of the tree:
[(0, ["val1"]), (2, ["val2"])]
If the Parser does succeed, it also returns the unconsumed input so that subsequent parsing stages can use it.
Now, curiously enough, the above Parser type exactly matches a well known monad transformer stack:
StateT s Maybe a
You can see this if you expand out the underlying implementation of StateT:
StateT s Maybe a ~ s -> Maybe (a, s)
This means we can just define:
import Control.Monad.Trans.State.Strict
type Parser a = StateT [(Int, [String])] Maybe a
If we do this, we get a Monad, Applicative and Alternative instance for our Parser type for free. This makes it very easy to define parsers!
First, we must define a primitive parser that consumes a single node of the tree:
parseElement :: Int -> Parser String
parseElement level = StateT $ \list -> case list of
[] -> Nothing
(level', strs):rest -> case strs of
[str] ->
if (level' == level)
then Just (str, rest)
else Nothing
_ -> Nothing
This is the only non-trivial piece of code we have to write, which, because it is total, handles all the following corner cases:
The list is empty
Your node has multiple values in it
The number in the tuple doesn't match the expected depth
The next part is where things get really elegant. We can then define two mutually recursive parsers, one for parsing a Tree, and the other for parsing a Forest:
import Control.Applicative
parseTree :: Int -> Parser (Tree String)
parseTree level = Node <$> parseElement level <*> parseForest (level + 1)
parseForest :: Int -> Parser (Forest String)
parseForest level = many (parseTree level)
The first parser uses Applicative style, since StateT gave us an Applicative instance for free. However, I could also have used StateT's Monad instance instead, to give code that's more readable for an imperative programmer:
parseTree :: Int -> Parser (Tree String)
parseTree level = do
str <- parseElement level
forest <- parseForest (level + 1)
return $ Node str forest
But what about the many function? What's that doing? Let's look at its type:
many :: (Alternative f) => f a -> f [a]
It takes anything that returns a value and implements Applicative and instead calls it repeatedly to return a list of values instead. When we defined our Parser type in terms of State, we got an Alternative instance for free, so we can use the many function to convert something that parses a single Tree (i.e. parseTree), into something that parses a Forest (i.e. parseForest).
To use our Parser, we just rename an existing StateT function to make its purpose clear:
runParser :: Parser a -> [(Int, [String])] -> Maybe a
runParser = evalStateT
Then we just run it!
>>> runParser (parseForest 0) [(0,["day 1"]),(1,["Person 1"]),(2,["Bill 1"]),(1,["Person 2"]),(2,["Bill 2"])]
Just [Node "day 1" [Node "Person 1" [Node "Bill 1" []],Node "Person 2" [Node "Bill 2" []]]]
That's just magic! Let's see what happens if we give it an invalid input:
>>> runParser (parseForest 0) [(0, ["val1"]), (2, ["val2"])]
Just [Node "val1" []]
It succeeds on a portion of the input! We can actually specify that it must consume the entire input by defining a parser that matches the end of the input:
eof :: Parser ()
eof = StateT $ \list -> case list of
[] -> Just ((), [])
_ -> Nothing
Now let's try it:
>>> runParser (parseForest 0 >> eof) [(0, ["val1"]), (2, ["val2"])]
Nothing
Perfect!
Flattening the Tree
To answer your second question, we again solve the problem using mutually recursive functions:
flattenForest :: Forest a -> [[a]]
flattenForest forest = concatMap flattenTree forest
flattenTree :: Tree a -> [[a]]
flattenTree (Node a forest) = case forest of
[] -> [[a]]
_ -> map (a:) (flattenForest forest)
Let's try it!
>>> flattenForest [Node "day 1" [Node "Person 1" [Node "Bill 1" []],Node "Person 2" [Node "Bill 2" []]]]
[["day 1","Person 1","Bill 1"],["day 1","Person 2","Bill 2"]]
Now, technically I didn't have to use mutually recursive functions. I could have done a single recursive function. I was just following the definition of the Tree type from Data.Tree.
Conclusion
So in theory I could have shortened the code even further by skipping the intermediate Tree type and just parsing the flattened result directly, but I figured you might want to use the Tree-based representation for other purposes.
The key take home points from this are:
Learn Haskell abstractions to simplify your code
Always write total functions
Learn to use recursion effectively
If you do these, you will write robust and elegant code that exactly matches the problem.
Appendix
Here is the final code that incorporates everything I've said:
import Control.Applicative
import Control.Monad.Trans.State.Strict
import Data.Tree
type YourType = [(Int, [String])]
type Parser a = StateT [(Int, [String])] Maybe a
runParser :: Parser a -> [(Int, [String])] -> Maybe a
runParser = evalStateT
parseElement :: Int -> Parser String
parseElement level = StateT $ \list -> case list of
[] -> Nothing
(level', strs):rest -> case strs of
[str] ->
if (level' == level)
then Just (str, rest)
else Nothing
_ -> Nothing
parseTree :: Int -> Parser (Tree String)
parseTree level = Node <$> parseElement level <*> parseForest (level + 1)
parseForest :: Int -> Parser (Forest String)
parseForest level = many (parseTree level)
eof :: Parser ()
eof = StateT $ \list -> case list of
[] -> Just ((), [])
_ -> Nothing
flattenForest :: Forest a -> [[a]]
flattenForest forest = concatMap flattenTree forest
flattenTree :: Tree a -> [[a]]
flattenTree (Node a forest) = case forest of
[] -> [[a]]
_ -> map (a:) (flattenForest forest)
I seem to have solved it.
group :: [(Integer, [String])] -> [[String]]
group ((n, str):ls) = let
(children, rest) = span (\(m, _) -> m > n) ls
subgroups = map (str ++) $ group children
in if null children then [str] ++ group rest
else subgroups ++ group rest
group [] = []
I didn't test it much though.
The idea is to notice the recursive pattern. This function takes the first element (N, S) of the list and then gathers all entries in higher levels until another element at level N, into a list 'children'. If there are no children, we are at the top level and S forms the output. If there are some, S is appended to all of them.
As for why your algorithm doesn't work, the problem is mostly in row. Notice that you are not descending recursively.
Trees can be used too.
data Tree a = Node a [Tree a] deriving Show
listToTree :: [(Integer, [String])] -> [Tree [String]]
listToTree ((n, str):ls) = let
(children, rest) = span (\(m, _) -> m > n) ls
subtrees = listToTree children
in Node str subtrees : listToTree rest
listToTree [] = []
treeToList :: [Tree [String]] -> [[String]]
treeToList (Node s ns:ts) = children ++ treeToList ts where
children = if null ns then [s] else map (s++) (treeToList ns)
treeToList [] = []
The algorithm is essentially the same. The first half goes to the first function, the second half to the second.
Related
With the following data type
data Tree a = Node a [Tree a]
I would like to create the following function:
labels:: Tree a -> [a]
labels (Node label children) = label: (map labels children)
but this fals as
* Occurs check: cannot construct the infinite type: a ~ [a]
Expected type: [a]
Actual type: [[a]]
Having children as x:xs didnt help either as xs would still be a list of trees and not a single tree.
Your function labels has type Tree a -> [a]. This thus means that if you construct a map labels, it has type map labels :: [Tree a] -> [[a]]. You thus need to concatenate these items, such that we produce a list [a] instead of [[a]].
You can use concatMap :: Foldable f => (a -> [b]) -> f a -> [b] instead:
labels :: Tree a -> [a]
labels (Node label children) = label : concatMap labels children
Having children as x:xs didnt help either as xs would still be a list of trees and not a single tree.
Indeed, furthermore by using (x:xs) you will (unnecessary) restrict yourself to trees with a non-empty list of children. It is a common misconception that x and xs are "special" variable names in (x:xs). You just pattern match on the "cons" data constructor (:).
You need join to convert [[a]] to [a], which comes from monad laws.
For example:
module Tree where
import Data.Functor.Foldable.TH
import Data.Functor.Foldable
import Control.Monad (join)
data Tree a = Tree a [Tree a] deriving stock Show
makeBaseFunctor ''Tree
labels :: Tree a -> [a]
labels = cata $ \case
TreeF a y -> a : join y
I want to write a function which takes a list as input value and manipulates it the following way:
Step 1: Put every 3 elements of the list in a sublist.
Should there remain less then 3 elements the remaining elements are put together in a specific sublist which is not going to be relevant in Step 2.
Step 2: Reverse the order of the elements in the created sublists.
The first element should be placed at the position of the third element, the second at the position of first element and the third element at the position of the second element. ([1,2,3] transformed to [2,3,1])
Example:
[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17]
-- should be transformed to
[[2,3,1],[5,6,4],[8,9,7],[11,12,10],[14,15,13],[16,17]]
So far I found the following approach to put every 3 elements together in sublists but I am not quite sure how to change the order of the elements in every sublist to match the requirements.
splitEvery :: Int -> [a] -> [[a]]
splitEvery _ [] = []
splitEvery n xs = as : splitEvery n bs
where (as,bs) = splitAt n xs
If the inner lists are always 3 elements, then you can hardcode that fact and use a simple solution like this:
f :: [a] -> [[a]]
f [] = []
f (x1:x2:x3:xs) = [x2,x3,x1]:f xs
f xs = [xs]
You can achieve your goal using take and drop as well
f [] = []
f xs = (take 3 xs) : f2 (drop 3 xs)
Idiomatic Haskell would be much better than other answers here. Basically, try to always design the API so it contains the proof that no corner case could occur. Hardcoding literals or hardcoding flip-like operations on lists (without guarantees of its length) are ALWAYS BAD.
{-# LANGUAGE LambdaCase #-}
divide : [a] -> [Either [a] (a,a,a)]
divide = \case
[] -> []
t1:t2:t3:ts -> Right (t1,t2,t3) : divide ts
ts -> [Left ts]
process :: [Either [a] (a,a,a)] -> [[a]]
process = fmap (flatten . flipEls) where
flipEls = fmap $ \(t1,t2,t3) -> [t2,t1,t3]
flatten = either id id
Now, you can just it like process . divide
Here is the expected input/output:
repeated "Mississippi" == "ips"
repeated [1,2,3,4,2,5,6,7,1] == [1,2]
repeated " " == " "
And here is my code so far:
repeated :: String -> String
repeated "" = ""
repeated x = group $ sort x
I know that the last part of the code doesn't work. I was thinking to sort the list then group it, then I wanted to make a filter on the list of list which are greater than 1, or something like that.
Your code already does half of the job
> group $ sort "Mississippi"
["M","iiii","pp","ssss"]
You said you want to filter out the non-duplicates. Let's define a predicate which identifies the lists having at least two elements:
atLeastTwo :: [a] -> Bool
atLeastTwo (_:_:_) = True
atLeastTwo _ = False
Using this:
> filter atLeastTwo . group $ sort "Mississippi"
["iiii","pp","ssss"]
Good. Now, we need to take only the first element from such lists. Since the lists are non-empty, we can use head safely:
> map head . filter atLeastTwo . group $ sort "Mississippi"
"ips"
Alternatively, we could replace the filter with filter (\xs -> length xs >= 2) but this would be less efficient.
Yet another option is to use a list comprehension
> [ x | (x:_y:_) <- group $ sort "Mississippi" ]
"ips"
This pattern matches on the lists starting with x and having at least another element _y, combining the filter with taking the head.
Okay, good start. One immediate problem is that the specification requires the function to work on lists of numbers, but you define it for strings. The list must be sorted, so its elements must have the typeclass Ord. Therefore, let’s fix the type signature:
repeated :: Ord a => [a] -> [a]
After calling sort and group, you will have a list of lists, [[a]]. Let’s take your idea of using filter. That works. Your predicate should, as you said, check the length of each list in the list, then compare that length to 1.
Filtering a list of lists gives you a subset, which is another list of lists, of type [[a]]. You need to flatten this list. What you want to do is map each entry in the list of lists to one of its elements. For example, the first. There’s a function in the Prelude to do that.
So, you might fill in the following skeleton:
module Repeated (repeated) where
import Data.List (group, sort)
repeated :: Ord a => [a] -> [a]
repeated = map _
. filter (\x -> _)
. group
. sort
I’ve written this in point-free style with the filtering predicate as a lambda expression, but many other ways to write this are equally good. Find one that you like! (For example, you could also write the filter predicate in point-free style, as a composition of two functions: a comparison on the result of length.)
When you try to compile this, the compiler will tell you that there are two typed holes, the _ entries to the right of the equal signs. It will also tell you the type of the holes. The first hole needs a function that takes a list and gives you back a single element. The second hole needs a Boolean expression using x. Fill these in correctly, and your program will work.
Here's some other approaches, to evaluate #chepner's comment on the solution using group $ sort. (Those solutions look simpler, because some of the complexity is hidden in the library routines.)
While it's true that sorting is O(n lg n), ...
It's not just the sorting but especially the group: that uses span, and both of them build and destroy temporary lists. I.e. they do this:
a linear traversal of an unsorted list will require some other data structure to keep track of all possible duplicates, and lookups in each will add to the space complexity at the very least. While carefully chosen data structures could be used to maintain an overall O(n) running time, the constant would probably make the algorithm slower in practice than the O(n lg n) solution, ...
group/span adds considerably to that complexity, so O(n lg n) is not a correct measure.
while greatly complicating the implementation.
The following all traverse the input list just once. Yes they build auxiliary lists. (Probably a Set would give better performance/quicker lookup.) They maybe look more complex, but to compare apples with apples look also at the code for group/span.
repeated2, repeated3, repeated4 :: Ord a => [a] -> [a]
repeated2/inserter2 builds an auxiliary list of pairs [(a, Bool)], in which the Bool is True if the a appears more than once, False if only once so far.
repeated2 xs = sort $ map fst $ filter snd $ foldr inserter2 [] xs
inserter2 :: Ord a => a -> [(a, Bool)] -> [(a, Bool)]
inserter2 x [] = [(x, False)]
inserter2 x (xb#(x', _): xs)
| x == x' = (x', True): xs
| otherwise = xb: inserter2 x xs
repeated3/inserter3 builds an auxiliary list of pairs [(a, Int)], in which the Int counts how many of the a appear. The aux list is sorted anyway, just for the heck of it.
repeated3 xs = map fst $ filter ((> 1).snd) $ foldr inserter3 [] xs
inserter3 :: Ord a => a -> [(a, Int)] -> [(a, Int)]
inserter3 x [] = [(x, 1)]
inserter3 x xss#(xc#(x', c): xs) = case x `compare` x' of
{ LT -> ((x, 1): xss)
; EQ -> ((x', c+1): xs)
; GT -> (xc: inserter3 x xs)
}
repeated4/go4 builds an output list of elements known to repeat. It maintains an intermediate list of elements met once (so far) as it traverses the input list. If it meets a repeat: it adds that element to the output list; deletes it from the intermediate list; filters that element out of the tail of the input list.
repeated4 xs = sort $ go4 [] [] xs
go4 :: Ord a => [a] -> [a] -> [a] -> [a]
go4 repeats _ [] = repeats
go4 repeats onces (x: xs) = case findUpd x onces of
{ (True, oncesU) -> go4 (x: repeats) oncesU (filter (/= x) xs)
; (False, oncesU) -> go4 repeats oncesU xs
}
findUpd :: Ord a => a -> [a] -> (Bool, [a])
findUpd x [] = (False, [x])
findUpd x (x': os) | x == x' = (True, os) -- i.e. x' removed
| otherwise =
let (b, os') = findUpd x os in (b, x': os')
(That last bit of list-fiddling in findUpd is very similar to span.)
My goal was to write a function to parse string of nested parentheses into a corresponding list:
parseParens "()" --> []
parseParens "(())" --> [[]]
parseParens "((()()))" --> [[[],[]]]
First off I discovered that I can't specify easily define a type of the return value. I could do something like:
parseParens :: String -> [[[[t]]]]
But how do I say that it's infinitely nested? I guess Haskell doesn't allow that.
My solution
I came up with my own data type:
data InfiniteList = EmptyList | Cons InfiniteList InfiniteList deriving (Show)
And a parser function that uses this:
parseParens :: String -> InfiniteList
parseParens ('(':xs) =
if remainder == ""
then result
else error "Unbalanced parenthesis"
where (result, remainder) = parseToClose EmptyList xs
parseParens _ = error "Unbalanced parenthesis"
parseToClose :: InfiniteList -> String -> (InfiniteList, String)
parseToClose acc "" = error "Unbalanced parenthesis!"
parseToClose acc (')':xs) = (acc, xs)
parseToClose acc ('(':xs) = parseToClose (concatInfLists acc (Cons result EmptyList)) remainder
where (result, remainder) = parseToClose EmptyList xs
concatInfLists :: InfiniteList -> InfiniteList -> InfiniteList
concatInfLists EmptyList ys = ys
concatInfLists (Cons x xs) ys = Cons x (concatInfLists xs ys)
Working like so:
parseParens "()" --> EmptyList
parseParens "(())" --> Cons EmptyList EmptyList
parseParens "((()()))" --> Cons (Cons EmptyList (Cons EmptyList EmptyList)) EmptyList
How to improve?
There surely must be a better way to do this. Perhaps there's even a way to use the built-in List data type for this?
Edit: Fixed my mischaracterization of Benjamin's answer.
While the answer in #Benjamin Hodgson's comment:
data Nested a = Flat a | Nested (Nested [a]) deriving (Show)
gives a good way to represent a homogeneous list of arbitrary nesting depth (i.e., sort of like a sum type of [a] plus [[a]] plus [[[a]]] plus all the rest), it seems like an unusual representation for your problem, particularly in a case like:
parseParens "(()(()))"
where the nesting depth of the "child nodes" differs. This would be represented as:
Nested (Nested (Nested (Flat [[],[[]]]))) :: Nested a
so it literally allows you to represent the result of the parse as the desired list, given enough Nested constructors, but it has some odd properties. For example, the innermost empty lists actually have different types: the first is of type [[a]] while the second is of type [a].
As a alternative approach, I think the data type you actually want is probably just:
data Nested = N [Nested] deriving (Show)
where each node N is a (possibly empty) list of nodes. Then, you'll get:
> parseParens "()"
N []
> parseParens "(())"
N [N []]
> parseParens "((()()))"
N [N [N [],N []]]
> parseParens "(()(()))"
N [N [],N [N []]]
If you just ignore the N constructors in these results, the first three of these match your "corresponding list" test cases from the beginning of your question.
As a side note: the Nested data type above is actually a "rose tree" containing no data, equivalent to Tree () using the Tree data type from Data.Tree in the containers package.
Finally, I can't emphasize enough how helpful it is to learn and use a monadic parsing library, even for simple parsing jobs. Using the parsec library, for example, you can write a parser for your grammar in one line:
nested = N <$> between (char '(') (char ')') (many nested)
My full code for parseParens is:
import Data.Tree
import Text.Parsec
import Text.Parsec.String
data Nested = N [Nested] deriving (Show)
nested :: Parser Nested
nested = N <$> between (char '(') (char ')') (many nested)
parseParens :: String -> Nested
parseParens str =
let Right result = parse (nested <* eof) "" str
in result
I want to make a function that looks up a String in a list of type [(String, Int)] and returns the Int paired with the String.
Like this:
λ> assignmentVariable "x" [("x", 3), ("y", 4), ("z", 1)]
3
Here's what I've tried:
assignmentVariable :: String -> [(String, Int)] -> Int
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n
then xs
else assignmentVariable
How could I write this?
Let's take the posted code:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
The first equation has only one argument, while the second has two. Let's fix that.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n (x:xs) = if x == n then xs else ...
Since we do x == n, these variables must be of the same type.
However, n::String and x::(String,Integer). We need to split x into its components before comparing.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then xs else ...
The result xs is a list, not an Integer as the type signature suggests. You just want x there.
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n then x else ...
Finally, the recursive call. When m/=n, we want to try the other pairs in the list xs, so:
assignmentVariable::String -> [(String, Integer)] -> Integer
assignmentVariable _ [] = error "list is empty"
assignmentVariable n ((m,x):xs) = if m == n
then x
else assignmentVariable n xs
You want to pattern-match on the pair.
assignmentVariable expected ((key, value) : rest)
If the variable name matches the expected name, the first element of the pair…
= if key == expected
You return the associated value, the second element of the pair.
then value
Otherwise, you try to find the value in the rest of the list.
else assignmentVariable expected rest
You can implement it without pattern-matching, of course:
assignmentVariable expected list
= if expected == fst (head list)
then snd (head list)
else assignmentVariable expected (tail list)
However, this is not the usual style in Haskell code.
This function also exists in the Prelude, by the name of lookup.
You're halfway there, actually!
First, it would be better to make a more general type signature, and a better name:
myLookup :: (Eq a) => a -> [(a, b)] -> b
You've done well to have sorted out the edge case of [], but you've not quite finished:
myLookup _ [] = error "myLookup: empty list."
myLookup n ((x, b):xs) = if x == n
then b
else myLookup n xs
Your problem was what you put after the else: you weren't recursively calling the function, you were returning the function, which doesn't make any sense - you need to call it again with different arguments to recur.
If you want to improve, try making a similar function of type Eq a => a -> [(a, b)] -> Maybe b for a challenge.
Just for posterity, I would like to propose an alternative implementation:
assignmentVariables :: Eq a => a -> [(a, b)] -> [b]
assignmentVariables n xs = [v | (n', v) <- xs, n == n']
You can run it in ghci:
> assignmentVariables "x" [("x", 3), ("y", 4), ("z", 1)]
[3]
"Ah!", I hear you say, "But it returns [3] and not 3!". But don't give up on it yet; there are several advantages of the behavior of this function over the behavior you proposed.
The type of assignmentVariables is more honest than the type of assignmentVariable. It doesn't promise to return a value when it doesn't find the given key in its lookup table. This means that, unlike your version, this version will not cause runtime crashes. Moreover, it has a clean way to report the unlikely situation where there are conflicts in the lookup table: it will return all values associated with the given key, even if there are many.
The consumer of the call then gets to decide how to handle the exceptional cases: one can write
case assignmentVariables key lookupTable of
[] -> -- do something appropriate to complain about missing keys
[value] -> -- do something with the value
values -> -- do conflict resolution; for example, use the first value or complain or something
or may simply treat the output of assignmentVariables as a nondeterministic value. The key here is that you are not locked into one behavior (which, of all the choices, crashing? really?).