Difference list head function time complexity - haskell

I'm playing with Difference list data type in Haskell: http://hackage.haskell.org/package/dlist-0.8.0.2/docs/Data-DList.html
And I see from package description that head function runs in O(n) time.
I wonder, why it happens? From first glance it looks like head should work O(1) time in most reasonable cases. But to argue about time-complexity we should define what this n stands for? Is it number of elements or number of lists?
Let's expand some definitions to figure out how head works.
First I have x = [1,2] and y = [3,4]. Then I convert them to DList and obtain x' = DList (x++) and y' = DList (y++). After that I append them:
z = x' <> y' = DList $ \zs -> x ++ (y ++ zs)
Now to the head function. It is defined as
-- | /O(n)/. Return the head of the dlist
head :: DList a -> a
head = list (error "Data.DList.head: empty dlist") const
Where list is:
-- | /O(n)/. List elimination for dlists
list :: b -> (a -> DList a -> b) -> DList a -> b
list nill consit dl =
case toList dl of
[] -> nill
(x : xs) -> consit x (fromList xs)
So you can say it is obvious why head runs O(n) time: is uses list function which runs O(n) time. But let's do some equational reasoning:
head z
= list (error "Data.DList.head: empty dlist") const z
= case toList z of
[] -> error "Data.DList.head: empty dlist"
(x : xs) -> const x (fromList xs)
= case (toList $ DList $ \zs -> x ++ (y ++ zs)) of
[] -> error "Data.DList.head: empty dlist"
(x : xs) -> const x (fromList xs)
= case (x ++ (y ++ [])) of
[] -> error "Data.DList.head: empty dlist"
(x : xs) -> const x (fromList xs)
= case ((1:2:[]) ++ (y ++ [])) of
[] -> error "Data.DList.head: empty dlist"
(x : xs) -> const x (fromList xs)
= case (1:((2:[]) ++ (y ++ []))) of
[] -> error "Data.DList.head: empty dlist"
(x : xs) -> const x (fromList xs)
= (1 : ((2:[]) ++ (y ++ []))) -> const 1 (fromList (2:[]) ++ (y ++ []))
= 1
So it looks like head won't evaluate whole list to take just first element and will work in O(1) unless there no empty lists. Is this really true and description of function just tells about worst possible case?

Related

create a function ved that will only remove the last occurrence of the largest item in the list using recursion

You must use recursion to define rmax2 and you must do so from “scratch”. That is, other than the cons operator, head, tail, and comparisons, you should not use any functions from the Haskell library.
I created a function that removes all instances of the largest item, using list comprehension. How do I remove the last instance of the largest number using recursion?
ved :: Ord a => [a] -> [a]
ved [] =[]
ved as = [ a | a <- as, m /= a ]
where m= maximum as
An easy way to split the problem into two easier subproblems consists in:
get the position index of the rightmost maximum value
write a general purpose function del that eliminates the element of a list at a given position. This does not require an Ord constraint.
If we were permitted to use regular library functions, ved could be written like this:
ved0 :: Ord a => [a] -> [a]
ved0 [] = []
ved0 (x:xs) =
let
(maxVal,maxPos) = maximum (zip (x:xs) [0..])
del k ys = let (ys0,ys1) = splitAt k ys in (ys0 ++ tail ys1)
in
del maxPos (x:xs)
where the pairs produced by zip are lexicographically ordered, thus ensuring the rightmost maximum gets picked.
We need to replace the library functions by manual recursion.
Regarding step 1, that is finding the position of the rightmost maximum, as is commonly done, we can use a recursive stepping function and a wrapper above it.
The recursive step function takes as arguments the whole context of the computation, that is:
current candidate for maximum value, mxv
current rightmost position of maximum value, mxp
current depth into the original list, d
rest of original list, xs
and it returns a pair: (currentMaxValue, currentMaxPos)
-- recursive stepping function:
findMax :: Ord a => a -> Int -> Int -> [a] -> (a, Int)
findMax mxv mxp d [] = (mxv,mxp)
findMax mxv mxp d (x:xs) = if (x >= mxv) then (findMax x d (d+1) xs)
else (findMax mxv mxp (d+1) xs)
-- top wrapper:
lastMaxPos :: Ord a => [a] -> Int
lastMaxPos [] = (-1)
lastMaxPos (x:xs) = snd (findMax x 0 1 xs)
Step 2, eliminating the list element at position k, can be handled in very similar fashion:
-- recursive stepping function:
del1 :: Int -> Int -> [a] -> [a]
del1 k d [] = []
del1 k d (x:xs) = if (d==k) then xs else x : del1 k (d+1) xs
-- top wrapper:
del :: Int -> [a] -> [a]
del k xs = del1 k 0 xs
Putting it all together:
We are now able to write our final recursion-based version of ved. For simplicity, we inline the content of wrapper functions instead of calling them.
-- ensure we're only using authorized functionality:
{-# LANGUAGE NoImplicitPrelude #-}
import Prelude (Ord, Eq, (==), (>=), (+), ($), head, tail,
IO, putStrLn, show, (++)) -- for testing only
ved :: Ord a => [a] -> [a]
ved [] = []
ved (x:xs) =
let
findMax mxv mxp d [] = (mxv,mxp)
findMax mxv mxp d (y:ys) = if (y >= mxv) then (findMax y d (d+1) ys)
else (findMax mxv mxp (d+1) ys)
(maxVal,maxPos) = findMax x 0 1 xs
del1 k d (y:ys) = if (d==k) then ys else y : del1 k (d+1) ys
del1 k d [] = []
in
del1 maxPos 0 (x:xs)
main :: IO ()
main = do
let xs = [1,2,3,7,3,2,1,7,3,5,7,5,4,3]
res = ved xs
putStrLn $ "input=" ++ (show xs) ++ "\n" ++ " res=" ++ (show res)
If you are strictly required to use recursion, you can use 2 helper functions: One to reverse the list and the second to remove the first largest while reversing the reversed list.
This result in a list where the last occurrence of the largest element is removed.
We also use a boolean flag to make sure we don't remove more than one element.
This is ugly code and I really don't like it. A way to make things cleaner would be to move the reversal of the list to a helper function outside of the current function so that there is only one helper function to the main function. Another way is to use the built-in reverse function and use recursion only for the removal.
removeLastLargest :: Ord a => [a] -> [a]
removeLastLargest xs = go (maximum xs) [] xs where
go n xs [] = go' n True [] xs
go n xs (y:ys) = go n (y:xs) ys
go' n f xs [] = xs
go' n f xs (y:ys)
| f && y == n = go' n False xs ys
| otherwise = go' n f (y:xs) ys
Borrowing the implementation of dropWhileEnd from Hackage, we can implement a helper function splitWhileEnd:
splitWhileEnd :: (a -> Bool) -> [a] -> ([a], [a])
splitWhileEnd p = foldr (\x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)) ([],[])
splitWhileEnd splits a list according to a predictor from the end. For example:
ghci> xs = [1,2,3,4,3,2,4,3,2]
ghci> splitWhileEnd (< maximum xs) xs
([1,2,3,4,3,2,4],[3,2])
With this helper function, you can write ven as:
ven :: Ord a => [a] -> [a]
ven xs =
let (x, y) = splitWhileEnd (< maximum xs) xs
in init x ++ y
ghci> ven xs
[1,2,3,4,3,2,3,2]
For your case, you can refactor splitWhileEnd as:
fun p = \x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)
splitWhileEnd' p [] = ([], [])
splitWhileEnd' p (x : xs) = fun p x (splitWhileEnd' p xs)
ven' xs = let (x, y) = splitWhileEnd' (< maximum xs) xs in init x ++ y
If init and ++ are not allowed, you can implement them manually. It's easy!
BTW, I guess this may be your homework for Haskell course. I think it's ridiculous if your teacher gives the limitations. Who is programming from scratch nowadays?
Anyway, you can always work around this kind of limitations by reimplementing the built-in function manually. Good luck!

How to apply a function to a specific element of a list

How can I apply a function to only a single element of a list?
Any suggestion?
Example:
let list = [1,2,3,4,3,6]
function x = x * 2
in ...
I want to apply function only to the first occurance of 3 and stop there.
Output:
List = [1,2,6,4,3,6] -- [1, 2, function 3, 4, 3, 6]
To map or not to map, that is the question.
Better not to map.
Why? Because map id == id anyway, and you only want to map through one element, the first one found to be equal to the argument given.
Thus, split the list in two, change the found element, and glue them all back together. Simple.
See: span :: (a -> Bool) -> [a] -> ([a], [a]).
Write: revappend (xs :: [a]) (ys :: [a]) == append (reverse xs) ys, only efficient.
Or fuse all the pieces together into one function. You can code it directly with manual recursion, or using foldr. Remember,
map f xs = foldr (\x r -> f x : r) [] xs
takeWhile p xs = foldr (\x r -> if p x then x : r else []) [] xs
takeUntil p xs = foldr (\x r -> if p x then [x] else x : r) [] xs
filter p xs = foldr (\x r -> if p x then x : r else r) [] xs
duplicate xs = foldr (\x r -> x : x : r) [] xs
mapFirstThat p f xs = -- ... your function
etc. Although, foldr won't be a direct fit, as you need the combining function of the (\x xs r -> ...) variety. That is known as paramorphism, and can be faked by feeding tails xs to the foldr, instead.
you need to maintain some type of state to indicate the first instance of the value, since map will apply the function to all values.
Perhaps something like this
map (\(b,x) -> if (b) then f x else x) $ markFirst 3 [1,2,3,4,3,6]
and
markFirst :: a -> [a] -> [(Boolean,a)]
markFirst a [] = []
markFirst a (x:xs) | x==a = (True,x): zip (repeat False) xs
| otherwise = (False,x): markFirst a xs
I'm sure there is an easier way, but that's the best I came up with at this time on the day before Thanksgiving.
Here is another approach based on the comment below
> let leftap f (x,y) = f x ++ y
leftap (map (\x -> if(x==3) then f x else x)) $ splitAt 3 [1,2,3,4,3,6]
You can just create a simple function which multiples a number by two:
times_two :: (Num a) => a -> a
times_two x = x * 2
Then simply search for the specified element in the list, and apply times_two to it. Something like this could work:
map_one_element :: (Eq a, Num a) => a -> (a -> a) -> [a] -> [a]
-- base case
map_one_element _ _ [] = []
-- recursive case
map_one_element x f (y:ys)
-- ff element is found, apply f to it and add rest of the list normally
| x == y = f y : ys
-- first occurence hasnt been found, keep recursing
| otherwise = y : map_one_element x f ys
Which works as follows:
*Main> map_one_element 3 times_two [1,2,3,4,3,6]
[1,2,6,4,3,6]

Haskell - output a type which takes 2 parametes

I'm trying to make an array of my own type letterCount in form of [('letter',occurance),(),...]. How can I make an output of a type which takes 2 parameters. Here's my code:
type LetterCount = (Char,Int)
letterOccur :: Char->[Char] -> Int
letterOccur c [] = 0
letterOccur c (x:xs) = if (c == x) then ((letterOccur c xs) + 1)
else letterOccur c xs
letterStats :: [Char] -> [LetterCount]
letterStats :: [] = []
letterStats (x:xs) = [x,(letterOccur x (x:xs))] ++ letterStats xs
I'm guessing you're trying to do something like this:
letterStats :: [Char] -> [LetterCount]
letterStats :: [] = []
letterStats (x:xs) = (x, (+1) $ letterOccur x xs) : letterStats xs
All you want to do is add +1 as you are not counting x when checking xs for all x occurances. Also what you want is to return a list of the letterCount type which is a Tuple not a list, therefore I changed
[x, letterOccur x xs] ++ letterStats xs
to
(x, (+1) $ letterOccur x xs) : letterStats xs
Although you could also do this:
[(x, (+1) $ letterOccur x xs)] ++ letterStats xs
But is unnecessary.

Define functions with foldl foldr

I understand the definitions of foldl, foldr, but I have problems with functions defined by them.
For example map with foldr:
map f [] = []
map f l = foldr (\x xs -> f x : xs) [] l
I don't understand the (\x xs -> f x : xs). It is the map function, which foldr takes? But shouldn't it be (\x xs -> f x : f xs), because map f (x:xs) = f x : map f xs?
Example with foldl:
concat (x:xs) = x ++ concat xs
concat' xs = foldl (++) [] xs
concat'' xs = foldl (\ys y -> ys ++ y) [] xs
Of course I understand (++), but what's the logic behind (\ys y -> ys ++ y)? Is it ys = [] and y = xs?
So the function takes [] as ys and y is the first element of xs and concates the [] with the y?
Concrete example:
concat'' [1,2,3] = foldl (\ys y -> ys ++ y) [] [1,2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [] [1]) [2,3]
=> foldl (\ys y -> ys ++ y) [1] [2,3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1] [2]) [3]
=> foldl (\ys y -> ys ++ y) [1,2] [3]
=> foldl (\ys y -> ys ++ y) ((\ys y -> ys ++ y) [1,2] [3]) []
=> foldl (\ys y -> ys ++ y) [1,2,3] []
=> [1,2,3]
Another thing: concat only takes 1 list xs, so if I want to concat 2 lists?
concat (x:xs) ys = x ++ concat xs ys
concat [1,2,3] [4,5,6] with foldl?
Reverse:
reverse (x:xs) = reverse xs ++ [x]
reverse' l = foldl (\xs x -> [x] : xs) [] l
reverse'' l = foldr (\x xs -> xs ++ [x]) [] l
The foldr is intuitive clear (with the questions from above), but what's behind the reverse order in foldl (\xs x -> [x] : xs)? This foldl (\x xs -> xs ++ [x]) [] l would be wrong, wouldn't it?
Thanks a lot!
The code
foldr (\x xs -> ...) end list
could be read, roughly, as follows
scan the whole list
if it's empty, just return end end
otherwise:
let x be the element at hand
let xs be the rest of the list, after having been processed
apply the ... operation
The emphasized part is crucial. xs is not the rest of the list, but the result of the "recursive call" on it.
Indeed, xs is a bad name for that. In thee general case, it's not even a list! E.g. one would never write (silly example)
foldr (\x xs -> x + xs) 0 [1..100] -- sum 1..100
but rather prefer something like
foldr (\x partialSum -> x + partialSum) 0 [1..100] -- sum 1..100
(Actually, one would not sum using foldr, but let's leave that aside.)
So, just read it like this:
map f l = foldr (\x mappedTail -> f x : mappedTail) [] l

Merging lists with unique elements

I am trying to combine two lists and remove duplicates.Following is my code but i think i have syntax error and also can anyone suggest a better method to implement this as i am sure there is a better way.
MY CODE
combine :: [Int] -> [Int] -> [Int]
combine (x:xs++y:ys)
|elem x xs || elem x ys = combine xs ++ ys
|elem y xs || elem y ys = combine xs ++ ys
|otherwise x:y:combine xs ys
I know what the problem wants me to do and i know how to solve it but i am not able to get over the syntax. Any help would be appreciated
The problem is you've defined the type of combine as taking two lists of ints and returning a list of ints, but you're defining combine as taking the combination of two lists. Also I believe otherwise requires the =
combine :: [Int] -> [Int] -> [Int]
combine x y
| null x && not (null y) = y
| null y && not (null x) = x
| null x && null y = []
| elem (head x) (tail x) || elem (head x) (tail y) = combine (tail x) y
| elem (head y) (tail x) || elem (head y) (tail y) = combine x (tail y)
| (head x) == (head y) = (head x) : combine (tail x) (tail y)
| otherwise = (head x) : (head y) : combine (tail x) (tail y)
This just smells like there's better ways. There's probably performance gain somewhere (scanning lists multiple times with elem, I'm looking at you). This code also looks like it's doing a lot of repeating itself too.
A much easier way is by using the nub function in Data.List.
import Data.List { nub }
combine:: [Int] -> [Int] -> [Int]
combine x y = nub (x ++ y)
After a short cabal install data-ordlist:
import Data.List.Ordered
combine x y = nubSort $ x ++ y
which runs a lot faster. wee!

Resources