How to solve Haskell parse error on input 'otherwise' - haskell

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.

Related

Simplify function for Haskell

I have this code, which in my opinion is too long. And I was wondering if there's a way for me to simplify or shorten it.
I have this helper-function swap which takes in two lists of integers and returns them after swapping a number from on to the other All lists have 5 ints in them, so I fill in with zeroes if there are less than that.
It looks like this:
-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
| xs == ys = [xs, ys] -- If both lists are all zeroes
| all (==0) ys = -- If the second list is all zeroes
let
e = head $ filter (/= 0) xs -- First non-zero element from first list
newX = replicate (length xs - length (filter (/= 0) xs) - 1) 0 ++ tail (filter (/= 0) xs)
newY = tail ys ++ [e]
in
[newX, newY]
| otherwise =
let
e = head $ filter (/= 0) xs -- First non-zero element from first list
newX = replicate (length xs - length (filter (/= 0) xs) + 1) 0 ++ tail (filter (/= 0) xs)
newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
in
[newX, newY]
I am using it in my function below, which is the function I feel like is too long:
move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
| a == b = error "a and b cannot be the same integer"
| a == 1 && b == 2 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head swapped, last swapped, last ints]
| a == 1 && b == 3 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head swapped, ints !! 1, last swapped]
| a == 2 && b == 1 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[last swapped, head swapped, last ints]
| a == 2 && b == 3 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head ints, head swapped, last swapped]
| a == 3 && b == 1 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[last swapped, ints !! 1, head swapped]
| a == 3 && b == 2 =
let
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
in
[head ints, last swapped, head swapped]
| otherwise = error "a and b must be either 1, 2 or 3"
This function takes in two ints and a list consisting of 3 lists of ints, where each list has 5 integers, so a sample input would be f.ex
[[1,2,3,4,5],[0,0,0,0,0],[0,0,0,0,0]] or
[[0,0,0,4,5],[0,0,0,2,3],[0,0,0,0,1]] or
[[0,0,3,4,5],[0,0,0,0,1],[0,0,0,0,2]]
So $a$ and $b$ can only be either 1,2, or 3. Giving me $2^3=6$ different cases to consder. Even If manage to get it down to two cases $a>b$ and $b>a$ I still get too many lines of code compared to what I expect is proper for Haskell. Is there any way of shortening this code?
This is not a full answer yet, but the start of one. Look how I removed all code duplication into where blocks. There are still plenty of opportunities of simplification.
-- Takes in two lists and moves one non-zero int from one to the other
swap :: [Int] -> [Int] -> [[Int]]
swap xs ys
| xs == ys = [xs, ys] -- If both lists are all zeroes
| all (==0) ys = -- If the second list is all zeroes
let
newX = replicate (length xs - length nonZeroXs - 1) 0 ++ tail nonZeroXs
newY = tail ys ++ [e]
in
[newX, newY]
| otherwise =
let
newX = replicate (length xs - length nonZeroXs + 1) 0 ++ tail nonZeroXs
newY = replicate (length (filter (==0) ys) - 1) 0 ++ [e] ++ drop (length xs - length (filter (/= 0) ys)) ys
in
[newX, newY]
where
nonZeroXs = filter (/= 0) xs
e = head $ filter (/= 0) xs -- First non-zero element from first list
The only difference between newXs is the signal of the the final addition. Which suggests that the entire decision block might be not be at it's best place.
move :: Int -> Int -> [[Int]] -> [[Int]]
move a b ints
| a == b = error "a and b cannot be the same integer"
| a == 1 && b == 2 = [head swapped, last swapped, last ints]
| a == 1 && b == 3 = [head swapped, ints !! 1, last swapped]
| a == 2 && b == 1 = [last swapped, head swapped, last ints]
| a == 2 && b == 3 = [head ints, head swapped, last swapped]
| a == 3 && b == 1 = [last swapped, ints !! 1, head swapped]
| a == 3 && b == 2 = [head ints, last swapped, head swapped]
| otherwise = error "a and b must be either 1, 2 or 3"
where
fst = ints !! (a-1)
snd = ints !! (b-1)
swapped = swap fst snd
Have a good look on the above and run some tests. I don't have the time to test it myself right now.

How to split a list of numbers into a set of list with all the numbers in Haskell

How do i split a list in Haskell, for example, "222 33244" into ["222","33","2","444"] only through recursion and fuctions on the prelude?
My current attempt is:
list xs
|length xs == 0 = ""
|otherwise = listSplit xs
listSplit (x:xs)
|x == head xs = x : ListSplitNext x xs
|otherwise = x:[]
listSplitNext a (x:xs)
|a == x = a : listSplitNext x xs
|otherwise = listSplit xs
So since I don't quite understand your approach and ghci lists 18 compile errors in your code, I'm afraid I can't help you with your attempt at a solution.
As pointed out in a comment, a possible solution would be:
listSplit xs = listSplit' [] (filter (`elem` ['0'..'9']) xs)
listSplit' ws (x:xs) = listSplit' (ws ++ [x : takeWhile (==x) xs]) (dropWhile (==x) xs)
listSplit' ws [] = ws
Filter every element of the string that is not a number (Data.Char.isNumber would do this, too, but the premise was to only use Prelude functions) and call listSplit' on the filtered list.
(ws ++ [x : takeWhile (==x) xs]) collects everything in xs until it reaches a letter that does not equal x, wraps this in a list and appends it to ws.
(dropWhile (==x) xs) removes every letter in xs until it reaches a letter that does not equal x.
Finally, the function calls itself with the updated ws and the reduced xs
If there are no more remaining elements, the function returns ws
If your goal is to use very few pre-defined functions this might give you some ideas:
listSplit :: String -> [String]
listSplit xs =
let (as, a) = foldr go ([], []) numbers
in a : as
where
isNumber x = x `elem` ['0'..'9']
numbers = filter isNumber xs
go cur (res, []) = (res, [cur])
go cur (res, lst#(a:_))
| a == cur = (res, a : lst)
| otherwise = (lst : res, [cur])
Of course you can replace foldr with your own recursion as well:
numberSplit :: String -> [String]
numberSplit xs =
let numbers = filter (`elem` ['0'..'9']) xs
in listSplit numbers
listSplit :: Eq a => [a] -> [[a]]
listSplit =
reverse . go [] []
where
go acc as [] = as : acc
go acc [] (x:xs) = go acc [x] xs
go acc as#(a:_) (x:xs)
| a == x = go acc (a : as) xs
| otherwise = go (as : acc) [x] xs
I had a moment to implement this but I think this is what you're looking for.
listSplit s = go filtered
where filtered = [c | c <- s, elem c ['0'..'9']]
go [] = []
go (x:xs) = (x : takeWhile (== x) xs) : (go $ dropWhile (== x) xs)

Structural Induction - (zip xs ys)!!n = (xs!!n, ys!!n)

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.

Haskell - Get middle numbers of a list

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

Problems with understanding splitAt in Haskell?

So I have found that the built-in splitAt function in Haskell can be defined as follows:
splitAt :: Int -> [a] -> ([a], [a])
-- Pre: n >= 0
splitAt n []
= ([], [])
splitAt n (x : xs)
= if n == 0
then ([], x : xs)
else (x : xs', xs'')
where
(xs', xs'') = splitAt (n - 1) xs
What I don't understand here/can't get my head around is the where part.
As an example,
splitAt 2 "Haskell" should return (["Ha"],["skell"]), but I don't really understand how it works here to define (x:xs',xs'') as another function? How would this look like visually?
With the example:
splitAt 2 "Haskell"
= (('H':xs',xs''))
^ so this then does splitAt 1 "askell", but I'm very confused as to what happens to the xs',xs'' in the tuple above...
Thanks.
(xs', xs'') = splitAt (n - 1) xs
This takes the result of splitAt (n - 1) xs, which is a pair, and assigns the name xs' to the first element of that pair (i.e. the first n - 1 elements of xs) and xs'' to the second element (i.e. the remaining elements).
(x:xs', xs'')
This produces a pair. The first element of that pair is a list that's the result of prepending x to xs' (i.e. to the first n-1 elements of xs). The second element is xs'' (i.e. the remaining elements of xs).

Resources