Given n >= 0 and n < min (length xs) (length ys)
show that (zip xs ys)!!n = (xs!!n, ys!!n) with structural Induction over xs.
Is it even possible to do this in a clean way? I cant find any spots where I can use the Induction Hypothesis.
First, I'll give definitions of zip and !!:
zip :: [a] -> [b] -> [(a,b)]
zip [] [] = [] -- (zip-1)
zip (x:xs) (y:ys) = (x,y) : zip xs ys -- (zip-2)
zip _ _ = [] -- (zip-3)
(!!) :: [a] -> Int -> a
(x : _) !! 0 = x -- (!!-1)
(_ : xs) !! n = xs !! (n - 1) -- (!!-2)
Let xs, ys and n arbitrary. Now, suppose that n >=0 and n < min (length xs) (length ys). We proceed by induction on xs.
Case xs = []. Now we do case analysis on ys. In both cases, we have that there's no n >=0 and n < min (length xs) (length ys). So, this case is trivially true.
Case xs = x : xs'. We proceed by case analysis on ys.
Case xs = x : xs' and ys = []. Again, we have the theorem trivially true since there's no n such that that n >=0 and n < min (length xs) (length ys).
Case xs = x : xs' and ys = y : ys'. Now we do case analysis on n.
Case xs = x : xs', ys = y : ys' and n = 0. We have that
zip (x : xs') (y : ys') !! 0 = {by equation (zip-2)}
(x,y) : zip xs' ys' !! 0 = {by equation (!!-1)}
(x,y) = {by equation (!!-1) - backwards}
((x : xs') !! 0, (y : ys') !! 0).
Case xs = x : xs', ys = y : ys' and n = n' + 1.
zip (x : xs') (y : ys') !! (n + 1) = {by equation zip-2}
(x,y) : zip xs' ys' !! (n + 1) = {by equation (!!-2)}
zip xs' ys' !! n = {by induction hypothesis}
(xs' !! n , ys' !! n) = {by equation (!!-2) backwards}
((x : xs') !! (n + 1), (y : ys') !! (n + 1))
QED
Hope that this helps.
Related
I have a function which returns a list of halves of palindromes found from the input list. It works if I use an if-statement on one row but I'd like to use guards. Guards give me a parse error. I read many cases giving this kind of error, but I didn't figure out my case. Here is the code:
palindromeHalfs :: [String] -> [String]
palindromeHalfs xs = map firstHalf (filter palindrome xs)
where
firstHalf :: String -> String
firstHalf ys | (length ys) `rem` 2 == 0 = take ((div (length ys 2)) ys
| otherwise = take ((div (length ys 2) + 1) ys
palindrome :: String -> Bool
palindrome str | str == reverse str = True
| otherwise = False
And the error:
palindromeHalfs.hs:6:20: error: parse error on input `otherwise'
|
6 | | otherwise = take ((div (length ys 2) + 1) ys
| ^^^^^^^^^
The function works if I replace
firstHalf ys | (length ys) `rem` 2 == 0 = take ((div (length ys 2)) ys
| otherwise = take ((div (length ys 2) + 1) ys
with
firstHalf ys = if (length (ys !! 0)) `rem` 2 == 0 then take ((div (length (ys !! 0)) 2)) ys
else take ((div (length (ys !! 0)) 2) + 1) ys
In my code the if-statement is one row, it didn't fit here. I'd appreciate if someone can tell me which is preferred, if or guards. And of course, why my guards do not work.
The parentheses are not balanced in
take ((div (length ys 2)) ys
As for style, guards are much preferred over if/else in cases where either may be used. Note also that even :: Integral a => a -> Bool is a function that exists; you don't have to invent it with rem.
I'm attempting to take in a string, evaluate, and output the answer. For example: if the input is the string "2*(3+10)" then the output should be the int 26
At the moment, It isn't working. I'm having problems with white space. If there is white space in the code input, I get ***Exception: Char.digitToInt: not a digit ' '. If there is NO whitespace in the input i get *** Exception: Prelude.!!: index too large
import Data.Char
parseExpr :: String -> Int
parseExpr str = start(trim (str))
trim :: [Char] -> [Char]
trim xs = [ x | x <- xs, not (isSpace x)]
start :: [Char] -> Int
start xs = expression xs 0
expression :: [Char] -> Int -> Int
expression xs i
|(xs !! (((basic xs i (-1))!! 1)+1)) == '+' = (multiply xs ((basic xs i (-1))!! 1)) + (multiply xs ((basic xs (i+2) (-1))!! 0))
|(xs !! (((basic xs i (-1))!! 1)+1)) == '-' = (multiply xs ((basic xs i (-1))!! 1)) - (multiply xs ((basic xs (i+2) (-1))!! 0))
|otherwise = multiply xs i
multiply :: [Char] -> Int -> Int
multiply xs i
| (xs !! (((basic xs i (-1))!! 1)+1)) == '*' = (power xs ((basic xs i (-1))!! 0)) * (power xs ((basic xs (i+2) (-1))!! 0))
| (xs !! (((basic xs i (-1))!! 1)+1)) == '/' = (power xs ((basic xs i (-1))!! 0)) `div` (power xs ((basic xs (i+2) (-1))!! 0))
|otherwise = power xs i
power :: [Char] -> Int -> Int
power xs i
| (xs !! (((basic xs i (-1))!! 1)+ 1)) == '^' = (((basic xs i (-1))!! 0) ^ ((basic xs (i+2) (-1))!! 0))
|otherwise = (basic xs i (-1)) !! 0
basic :: [Char] -> Int -> Int -> [Int]
basic xs i pnum
| pnum > (-1) && (isDigit(xs !!(i+1))) = basic xs (i+1) (pnum*10 + (digitToInt(xs !! i)))
| isDigit(xs !! i ) && isDigit(xs !!(i+1)) = basic xs (i+1) (digitToInt (xs !! i))
| pnum > (-1) && not (isDigit(xs !!(i+1))) = [pnum, i] -- + digitToInt(xs !! i)
| xs !! i == '-' = [(-(basic xs (i+1)(-1)) !! 0) , i] -- may want to delete if add/sub can handle
| xs !! i == '(' = [(expression xs (i+1)), i]
| xs !! i == ')' = [(expression xs (i+1)), i] --This may not work here
| otherwise = [digitToInt (xs !! i), i]
I want to reorder a list in the following way:
[5,6,7,8,9] -> [7,5,9,6,8]
[6,7,8,5,4,3] -> [8,5,6,3,7,4]
It's supposed to get the middle number or numbers of the list and put them in the starting position. After that it should start to get the two outer numbers of the list and add them in and work its way in.
I have the following code to get the middle numbers and put them into the beginning of the list but can't figure out how to start adding the outer numbers into the new list.
-- import Data.List
-- import System.IO
longitude xs = length xs
middle xs = length xs `div` 2
addOne xs = middle xs - 1
oneMore xs = length xs - 1
otherCase xs = oneMore xs `div` 2
valuea xs = xs !! middle xs
valueb xs = xs !! addOne xs
valuec xs = xs !! otherCase xs
modulus xs = longitude xs `mod` 2
order xs = midNums xs
takes xs = take (otherCase xs) xs
oddOne xs = otherCase xs + 1
takeX xs = drop (oddOne xs) xs
value xs = takes xs ++ takeX xs
reorder xs = drop (otherCase xs )(take (middle xs + 1) xs)
valueOdd xs = reorder xs ++ takes xs ++ takeX xs
paruno xs = drop (middle xs + 1) xs
pairTwo xs = take (addOne xs) xs
midPair xs = take (addOne xs)(drop (middle xs -1) xs)
--Get the numbers
midNums xs = if modulus xs == 0 then midPair xs ++ paruno xs ++ pairTwo xs
else valueOdd xs
I want it to work like this: Demo
Try this:
f :: (Num a) => [a] -> [a]
f [] = []
f [x] = [x]
f xs = if len `mod` 2 == 1 then flatten [xs !! half] else flatten [xs !! (half-1), xs !! half]
where len = length xs
half = len `div` 2
firsthalf = take (half-1) xs
secondhalf = (reverse . take half . drop (half+1)) xs
outtoin = zipWith (\x y -> x:y:[]) firsthalf secondhalf
flatten = concat . flip (:) outtoin
Breaking it down:
First get the midpoint(s)
Next get the two halves of the list excluding middle elements
Build the list from outside inwards using zip
Concatenate the zip result to flatten and add to the middle elements list
Demo
Here is my implementation:
mergesort :: (Ord a) => [a] -> [a]
mergesort list = merge (mergesort (left list)) (mergesort (right list))
where
left xs = take (div (length xs) 2) xs
right xs = drop (div (length xs) 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
The code compiles but when I run it my machine crashes. What am I doing wrong?
You are missing base cases - so you get infinite recursion. Trying stepping through your example with lists like [] or [1] and you'll fall straight into the problem.
mergesort :: (Ord a) => [a] -> [a]
mergesort [] = [] -- < ADDED
mergesort [x] = [x] -- < ADDED
mergesort list = merge (mergesort (left list)) (mergesort (right list))
where
left xs = take (div (length xs) 2) xs
right xs = drop (div (length xs) 2) xs
merge [] ys = ys
merge xs [] = xs
merge (x:xs) (y:ys)
| x <= y = x : merge xs (y:ys)
| otherwise = y : merge (x:xs) ys
I want to double every second element of a list. Here is the code-
doubleSec n [] = []
doubleSec n (x:xs)
| n==1 = x*2 : doubleSec 0 xs
| otherwise = x : doubleSec 1 xs
doubleSecond xs =
doubleSec 0 xs
How can I compact this logic in a single function?
You can match a pattern on the list like this
doubleSec :: [Int] -> [Int]
doubleSec [] = []
doubleSec [x] = [x]
doubleSec (x : y : xs) = x : 2* y : doubleSec xs
letting you do specific things to the second element
How about this
doubleSecond xs = map (\(x,i) -> if odd i then x*2 else x) (zip xs [0..])
This method will preserve the O(n) running time:
doubleSecond xs =
[ if isOddStep then 2 * x else x |
(isOddStep, x) <- zip (cycle [False, True]) xs ]
An more succinct version by #DavidFletcher:
doubleSecond = zipWith ($) (cycle [id, (2*)])
or:
doubleSecond = zipWith id (cycle [id, (2*)])
as suggested by #Carl.