basic Haskell: defining sorting function by recursion - haskell

So I have slight problem with sorting function. I need to define (using recursion) a function i, that takes as an argument a list of arguments a (this list needs to belong to Ord), which outputs ordered list of elements of type a.
Example:
i [3,2,1] = [1,2,3]
I have managed to come with this solution:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs : x
But it doesn't compute, outputting many errors. What is wrong?

Let me give you some hints to get you started. First of all, let's fix the formatting:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs : x
This throws an error which says:
In the first argument of ‘(:)’, namely ‘i xs’
In the expression: i xs : x
Now, this expression i xs : x is problematic. The type of (:) is (:) :: a -> [a] -> [a]. But in your expression you are passing a list instead of a value. What you meant to use was possibly ++. Using that fixes the compile error:
i :: Ord a => [a] -> [a]
i [] = []
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs ++ [x]
Now, if you try it in ghci, you will get a runtime exception:
ghci> i [3,2,1]
*** Exception: Prelude.head: empty list
Can you guess why ? That's because you haven't handled the case where the list is of length 1. So handling the case will give you this:
i :: Ord a => [a] -> [a]
i [] = []
i (x:[]) = [x]
i (x:xs)
| x <= head (xs) = x: i xs
| otherwise = i xs ++ [x]
Now, you may think that this works:
ghci> i [3,2,1]
[1,2,3]
ghci> i [3,1,2]
[1,2,3]
But it doesn't actually work, because there is a flaw in your algorithm. Just comparing the first two elements of the list won't give you an sorted array.
ghci> i [2,1,3]
[1,3,2]
I hope this is enough to get you started.

Related

Generating a set using higher order functions and unions

I am studying a past exam and I came across a question where I must write a function called setFunc to generate a set where I apply a function on each element in a list of tuples (which are a result of the Cartesian product operation)
First I implemented a helper function to take the union of sets:
Then I tried to implement the main function:
setFunc x y = f x y
setFunc (x:xs) (y:ys) = (f x y) OrdUnion (setFunc f xt ys)
Help on fixing setFunc would be appreciated.
I must use ordUnion somehow and I am not permitted to use sort.
This sort of constraint is expected to appear within the body of the question.
A core part of the problem is that we want the output list to be sorted (from your example), but we are told nothing about possible order-preserving properties of the argument function. So we must accept that the f x y output values will be produced in some unpredictable random order.
For example, we expect this equality to hold:
setFunc (*) [-7,2] [-7,3] == [-21,-14,6,49]
that is, the maximal output value results from the two minimal input values.
Hence, we are somewhat coerced into solving the problem in 2 steps:
produce the f x y output values in whatever order
sort the list produced in step 1.
Let's call the step 1 function cartesianFunc. It is easy to write it in recursive fashion:
cartesianFunc :: Ord c => (a -> b -> c) -> [a] -> [b] -> [c]
cartesianFunc f [] ys = []
cartesianFunc f (x:xs) ys = (map (f x) ys) ++ (cartesianFunc f xs ys)
Note that we have dropped the useless Ord constraints on types b and c.
Testing:
$ ghci
GHCi, version 8.8.4: https://www.haskell.org/ghc/ :? for help
...
λ>
λ> :load q13784671.hs
[1 of 1] Compiling Main ( q13784671.hs, interpreted )
Ok, one module loaded.
λ>
λ> cartesianFunc (*) [1,2,4] [1,3,9]
[1,3,9,2,6,18,4,12,36]
λ>
Now for step 2:
We may not use the library sort function. But we have to use function ordUnion, which merges two ordered lists into a bigger ordered list.
Assuming we had yet another function, say splitHalf, which could split a list into two roughly equal parts, we could obtain our own sort function by:
splitting the input list
recursively sorting its two halves
combining our two sorted halves using the merging ordUnion function.
To split a list, we can use the well-know tortoise-hare algorithm where at each iteration, the first part advances by one step and the second part advances by two steps.
This gives this code:
ordUnion :: (Ord a) => [a] -> [a] -> [a]
ordUnion a [] = a
ordUnion [] b = b
ordUnion (x:xs) (y:ys) = case compare x y of
LT -> x : ordUnion xs (y:ys)
EQ -> x : ordUnion xs ys
GT -> y : ordUnion (x:xs) ys
splitHalfTH :: [a] -> ([a],[a])
splitHalfTH xs = th xs xs
where
th (y:ys) (_:_:zs) = let (as,bs) = th ys zs in (y:as, bs)
th ys _ = ([],ys)
mySort :: (Ord a) => [a] -> [a]
mySort [] = []
mySort [a] = [a]
mySort xs = let (as,bs) = splitHalfTH xs in ordUnion (mySort as) (mySort bs)
and finally we can come up with our setFunc function by combining mySort and cartesianFunc:
setFunc :: Ord c => (a -> b -> c) -> [a] -> [b] -> [c]
setFunc fn xs ys = mySort (cartesianFunc fn xs ys)
Testing:
λ>
λ> cartesianFunc (*) [1,2,4] [1,3,9]
[1,3,9,2,6,18,4,12,36]
λ>
λ> mySort $ cartesianFunc (*) [1,2,4] [1,3,9]
[1,2,3,4,6,9,12,18,36]
λ>
λ> setFunc (*) [1,2,4] [1,3,9]
[1,2,3,4,6,9,12,18,36]
λ>

Haskell: compare sequences and count the length of the prefix that is common

Im new to haskell and Im writing a function that compares two sequences and reports the length of the prefix they have in common. This is what I have so far but it doesn't work for all cases.
commonLen :: Eq a => [a] -> [a] -> Int
commonLen (x:xs) [] = 0
commonLen (x:xs) (y:ys) | x==y = 1+(commonLen xs ys)
| otherwise = commonLen xs ys
Any ideas where im going wrong? Any help would be appreciated
You should not recurse in case x is different from y. In that case we return 0:
commonLen :: Eq a => [a] -> [a] -> Int
commonLen [] _ = 0
commonLen _ [] = 0
commonLen (x:xs) (y:ys) | x == y = 1 + commonLen xs ys
| otherwise = 0 -- &leftarrow; return 0
You also can avoid the explicit recursion, and work with:
commonLen :: Eq a => [a] -> [a] -> Int
commonLen xs ys = length (takeWhile id (zipWith (==) xs ys))
here we iterate over both lists concurrently, and compare the elements. We thus make a list of Bools that is True if the elements of the two lists match. Then we use takeWhile to take elements as long as the item is True, and we use length to determine the number of elements in that list. Due to Haskell's laziness, we will never evaluate the entire list if one of the elements differs from the corresponding element in the other list.

(x:xs) pattern Haskell logic

Let's say there is a simple function:
maximum' :: (Ord a) => [a] -> a
maximum' [] = error "maximum of empty list"
maximum' [x] = x
maximum' (x:xs) = max x (maximum' xs)
I understand the idea and what (x:xs) does. As it was explained in details here
What do the parentheses signify in (x:xs) when pattern matching?
but there is one little thing that I cannot get out of my head. Since cons: operator appends x to a list xs, why is it that x is the first element of function argument list and xs is the tail when we use (x:xs)??? as if (x:xs) calls head and tail on argument list.
This is just an instance of the general pattern that the constructor for a type is both used to construct elements of that type and to deconstruct. If you wrote
data MyList a = Empty | Cons a (MyList a)
you'd write
maximum' :: (Ord a) => MyList a -> a
maximum' Empty = error "maximum of empty list"
maximum' (Cons x Empty) = x
maximum' (Cons x xs) = max x (maximum' xs)
Except that lists are actually defined equivalently to
data [a] = [] | a:as
so, just as with other data types, : is used both to construct and to deconstruct nonempty lists.
The cons operator doesn't append, it prepends. That is x : xs produces a list that contains x as its first element and xs as the rest. Therefore the pattern x : xs likewise matches a list with x as the first element and xs as the rest.

Having trouble with H-15

I am doing Problem 15. Which states:
(**) Replicate the elements of a list a given number of times.
Example:
* (repli '(a b c) 3)
(A A A B B B C C C)
Example in Haskell:
> repli "abc" 3
"aaabbbccc"
My plan was to do something like this:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y | appendNo x y == [] = repli(xs) y
| otherwise = appendNo x y : (x:xs)
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)
Where I would make a function called appendNo that returns a list of 1 element y times then append it to the original list. Then take the body of the list and repeat this process until there are no more body elements left. But, I get the error:
H15.hs:6:30:
Couldn't match type `a' with `[a]'
`a' is a rigid type variable bound by
the type signature for repli :: [a] -> Integer -> [a] at H15.hs:3:1
In the return type of a call of `appendNo'
In the first argument of `(:)', namely `appendNo x y'
In the expression: appendNo x y : (x : xs)
Failed, modules loaded: none.
6:30 is at the on the p in appendNo in this line:
| otherwise = appendNo x y : (x:xs)
Ok thanks dave4420 I was able to figure it out by doing:
repli :: [a] -> Integer -> [a]
repli [] y = []
repli (x:xs) y = appendNo x y ++ repli(xs) y
where
appendNo :: a -> Integer -> [a]
appendNo a 0 = []
appendNo a y = a:appendNo a (y-1)
| otherwise = appendNo x y : (x:xs)
There is a type error in this line. So ask yourself:
What is the type of appendNo x y?
What is the type of (x:xs)?
What is the type of (:)?
Then you should be able to see why they don't match up.
If you still can't see why they don't match up, ask yourself
What is the type of x?
What is the type of xs?
What is the type of (:)?
Bear in mind that this time the types do match up.
As the problem is solved, let me give you a hint: You should try to think in transformations, not in "loops". Start with some concrete values like n = 3 and list = "ABCD". Then you should think along the lines "I need every element three times". There is already a function for doing the replication, which is surprisingly called replicate. So the sentence can be translated to map (replicate 3) "ABCD", which gives you ["AAA","BBB","CCC","DDD"]. That's almost what you want, you just need to concat the elements. This gives:
repli list n = concat (map (replicate n) list)
Because this operation is very common, there is a concatMap function combining concat and map, as well as the operator (>>=) doing the same, just with flipped arguments. So a very short solution would be:
repli list n = list >>= replicate n
This can be translated to the do-notation or a list comprehension as well:
repli list n = do
x <- list
y <- replicate n x
return y
repli list n = [y | x <- list, y <- replicate n x]

Multiply list elements by two or every element by (itself - 1)

i need to write a function, which takes positive integers list. If list begins with 2, then every element must be multiplied by 2, in other cases every integer n is written n-1 times.
two :: [Int] -> [Int]
i.e:
two [2,1] ==> [4,2]
two [3,2,4] ==> [3,3,2,4,4,4]
multiplyEveryoneByTwo :: [Int] -> [Int]
multiplyEveryoneByTwo [] = []
multiplyEveryoneByTwo [x] = [x*2]
multiplyEveryoneByTwo (x:xs) = (x*2) : multiplyEveryoneByTwo xs
replicateEveryone :: [Int] -> [Int]
replicateEveryone [] = []
replicateEveryone [x] = replicate (x-1) x
replicateEveryone (x:xs) = (replicate (x-1) x) ++ replicateEveryone xs
two :: [Int] -> [Int]
two [x] = if x == 2 then [x*2] else replicate (x-1) x
two (x:xs)
| x == 2 = multiplyEveryoneByTwo (x:xs)
| otherwise = replicateEveryone (x:xs)
I'm stuck now with writing that: if my first element of the list is 2, then recursively multiply every element by 2. I tried to do with extra function multiplyByTwo but it doesn't work.
The else statement is that i need to replicate every element of the list by (itself - 1)
is it correct approach to pass (x:xs) to my helper functions in here | x == 2 = multiplyEveryoneByTwo (x:xs) | otherwise = replicateEveryone (x:xs)
I would suggest separating your problems into two separate functions
multiplyEveryoneByTwo :: [Int] -> [Int]
multiplyEveryoneByTwo ...
replicateEveryone :: [Int] -> [Int]
replicateEveryone ...
After you have these two functions tested and working you can create your weird function that combines them
weirdf [] = ...
weirdf (x:xs)
| x == 2 = multiplyEveryone (...)
|otherwise = replicateEveryone (...)
Not a full answer (since your question was tagged as [homework]), but be careful with your function types. Note the following types:
two :: [Int] -> [Int]
but multiplyByTwo probably has a type like
multiplyByTwo :: Int -> Int
Therefore, you have a typing error when you write
two (x:xs) = if ... then multiplyByTwo x else ...
The type of the if-then-else expression must match the return type of two. Also, check the types of the two branches (the then and the else): do they return an expression of the same type? If not, you have another type error.

Resources