I am trying to solve a simple problem on HackerRank and am receiving the error in the title. The problem asks to take in a string and reduce it by removing adjacent pairs of letters. So "aabcdd" => "bc" for example. Here's my code:
main :: IO()
main = do
line <- getLine
putStrLn (reduce' line)
reduce' :: String -> String
reduce' [] = []
reduce' (x0:x1:xs)
| x1:xs == [] = [x0]
| x0 == x1 = reduce' xs
| otherwise = x0 : x1 : reduce' xs
I am confused because I think I have the edge cases covered. I don't want an answer to the problem, I just want to know why I am getting the error. Thanks!
You are not matching the case where you have only one element in the list
reduce' :: String -> String
reduce' [] = []
reduce' [x] = [x]
reduce' (x0:x1:xs)
| x0 == x1 = reduce' xs
| otherwise = x0 : x1 : reduce' xs
This | x1:xs == [] = [x0] is the pattern matching added, so there is no need to check in the guards.
Related
So I'm trying to wrap my head around Haskell with my first project where i have a function encountering an error:
Exception: prelude.head: empty list.
selectNextGuess :: [[Card]] -> [Card]
selectNextGuess lst
| length lst >= 1250 = lst !! (div (length lst) 2)
| otherwise = newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- lst]
(_, newGuess) = head(sort valuesList)
Any advice in steering me in the right direction to solve this would be greatly appreciated.
Cheers
TL;DR: since a list can be empty, and there is no minimal element in the empty list, the way to return a list without the error is to maybe return a list, or rather to return a Maybe list.
If you call selectNextGuess [], lst inside the function selectNextGuess becomes []. Then, valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x) | x <- [] ] = [] is also an empty list. And then (_, newGuess) = head (sort valuesList) = head (sort []) = head [] is called.
But there is no head element in the empty list. This is what the error message is telling us. You called head with [], which is forbidden, because it has no answer.
The usual solution is to make this possibility explicit in the data type. We either have just one answer, for a non-empty list, or we have nothing:
data Maybe a = Just a | Nothing
is such built-in type. So we can use it, and handle the empty lst explicitly:
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| null lst = Nothing
| otherwise = Just newGuess
where fbList = [[feedback x y | x <- lst, y <- lst]]
valuesList = [(calcValues(group $ sort[feedback y x | y <- lst, y /= x]), x)
| x <- lst]
(_, newGuess) = head (sort valuesList)
Using null as a guard like that is a bit of an anti-pattern. We usually achieve the same goal with the explicit pattern in a separate clause, like
selectNextGuess :: [[Card]] -> Maybe [Card]
selectNextGuess [] = Nothing
selectNextGuess lst
| length lst >= 1250 = Just $ lst !! (div (length lst) 2)
| otherwise = Just newGuess
where ......
Using that head ... sort ... combination to find the minimal element is perfectly fine. Due to Haskell's lazy evaluation and the library sort being implemented as bottom-up mergesort, it will take O(n) time.
There is also a shorter way to write down the same thing,
....
| otherwise = listToMaybe . map snd $ sort valuesList -- or,
= listToMaybe [ x | (_, x) <- sort valuesList ] -- whichever you prefer.
where fbList = .....
valuesList = .....
Since there is no more than one value "inside" a Maybe _, the conversion function listToMaybe already takes just head element, implicitly.
Moreover, it produces Nothing automatically in the empty list [] case. So the explicit pattern clause can be removed, this way.
This question already has answers here:
Non exhaustive pattern in function noThirds
(3 answers)
Closed 5 years ago.
I'm not sure what I'm missing here, but I have been unable to get the pattern matching on checkDiff to work in the code below. GHCi report "non-exhaustive patterns in function checkDiff. The code is:
import Data.Array.Unboxed
primes :: [Int]
primes = 2 : oddprimes ()
where
oddprimes () = 3 : sieve (oddprimes ()) 3 []
sieve (p:ps) x fs = [i*2 + x | (i,True) <- assocs a]
++ sieve ps (p*p) ((p,0) :
[(s, rem (y-q) s) | (s,y) <- fs])
where
q = (p*p-x)`div`2
a :: UArray Int Bool
a = accumArray (\ b c -> False) True (1,q-1)
[(i,()) | (s,y) <- fs, i <- [y+s, y+s+s..q]]
takePrimes :: [Int] -> [(Int,Int)]
takePrimes [] = []
takePrimes [x] = []
takePrimes (x:y:zs) = if y - x > 2 then (x,y) : takePrimes (y:zs) else takePrimes (y:zs)
checkDiff :: [(Int,Int)] -> Int
checkDiff [] = 0
checkDiff [(0,_)] = 0
checkDiff [(_,0)] = 0
checkDiff [(a,b)] = sum $ [x | x <- [(a + 1)..(b - 1)], totalFactors a == totalFactors (a + 1)]
totalFactors :: Int -> Int
totalFactors n = length $ [x | x <- [2..(div n 2)], rem n x == 0]
Please help.
checkDiff only handles lists of length zero and one. It is probably called with a longer list, triggering the non-exhaustiveness error.
You should turn on warnings with the -Wall flag. If you do, GHC will report such problems at compile time instead.
i have some troubles here with this.
I'm trying to do something like that:
Prelude> func ["abacate", "aba", "baaba"]
["cate", "", "ba"]
this exercise, must return words without the substring aba.
elimLetras :: String -> String
elimLetras [] = []
elimLetras (x:y:z:xs)
| elem x "aA" || elem y "bB" || elem z "aA" = elimLetras xs
| otherwise = x : elimLetras (x:xs)
| otherwise = y : elimLetras (y:xs)
| otherwise = z : elimLetras (z:xs)
elimLetras (x:xs) = x:xs
this code it's not working right.
On ghci, i'ts return:
prelude> elimLetras "abacate"
output: "cce"
Any tips?
So you are trying to remove the case insensitive substring aba from a String. Your method of checking for a substring isn't bad. It wouldn't scale very well but you can keep it like this if you want. The main issue is with the multiple otherwise statements. You should only ever have one otherwise statement, as only the first one will ever be reached.
Here is a rewrite of your function with a couple of helper function:
import Data.Char (toLower)
elimLetras :: String -> String
elimLetras (x:y:z:xs)
| stringEquals "aba" [x,y,z] = elimLetras xs
| otherwise = x : elimLetras (y:z:xs)
elimLetras xs = xs -- anything that has fewer than 3 letters is returned "as is".
-- Check if two strings are the same (case insensitive)
stringEquals :: String -> String -> Bool
stringEquals a b = stringToLower a == stringToLower b
stringToLower :: String -> String
stringToLower [] = []
stringToLower (x:xs) = toLower x : stringToLower xs
If you know about the map function, here is how I would probably write it:
elimLetras' :: String -> String
elimLetras' (x:y:z:xs)
| "aba" == map toLower [x,y,z] = elimLetras' xs
| otherwise = x : elimLetras' (y:z:xs)
elimLetras' xs = xs
movex [] a s = []
movex (x:xs) a s
| elem a x = moveNow x a s
| otherwise = x : (movex xs a s)
where
moveNow x a s
| s == 'l' = moveNow2 x a
where
moveNow2 [] _ = []
moveNow2 (x:y:xs) a
| x == ' ' && y == a = a : x : moveNow2 (y:xs) a
| otherwise = x : moveNow2 (y:xs) a
<- This is what I got right now
I am trying to make a function that iterates through [string], finds the right string and then mutates it.
given input
func ["abc", "dfg"] f l -- move f in this list 1 space left --
expected output
["abc", "fdg"]
Right now I am stuck at movex function that gives me error
Couldn't match expected type `Char' with actual type `[Char]'
In the first argument of `(:)', namely `x'
In the expression: x : (movex xs a s)
Direct solution to the error is to replace the line
| elem a x = moveNow x a s
With
| elem a x = moveNow x a s : movex xs a s
Or, probably
| elem a x = moveNow x a s : xs
Depending on what you want to do after the first match: continue looking for certain character, or leave other strings untouched.
Your moveNow function has return type String, or [Char], while movex has [String], or [[Char]], that's why compiler complains.
To avoid such problems(or fix them easier) consider writing explicit type signatures, like so:
movex :: [String]->String->String->[String]
I am trying to format text to be in the shape of a rectangle; currently I have been able to get it properly left justified, but the last line does not extend as far as possible.
I am trying to calculate the optimum field width in order to minimise or remove this entirely.
I am totally stuck. The code below shows the relevant functions. At the moment it gets stuck in an infinite loop.
Where am I going wrong?
On a side note, what is the best way of debugging Haskell code?
(Yes, I'm very new to this.)
optimumFieldWidth is supposed to compare line lengths until the length of the top line is equal to that of the bottom line, then return the field width which causes this to be true.
module Main where
import System
import Data.List
main = do
(f:_) <- getArgs
xs <- getContents
putStr (show (bestFieldWidth maxLineLength xs))
bestFieldWidth :: Int -> String -> Int
bestFiledWidth _ [] = 0
bestFieldWidth lineLength xs
| length (last input) == length (head input) = lineLength
| otherwise = bestFieldWidth (length (head (rect (lineLength-1) xs))) xs
where input = lines xs
rect :: Int -> String -> [String]
rect _ [] = []
rect lineLength xs
| length input <= len = [input]
| otherwise = take len input : rect len (drop len input)
where input = trim xs
len = bestFieldWidth lineLength xs
maxLineLength :: Int
maxLineLength = 40
All responses are appreciated. Thank you.
I thought I'd put the actual solution here in case any other nutters wish to do this.
Please bear in mind that it was written by a moron so it probably isn't the most elegant solution.
maxFieldWidth :: Int
maxFieldWidth = 30
rect :: String -> String
rect xs = (unlines (chunk (bestFieldWidth (maxFieldWidth) (lines input)) input))
where input = itemsReplace '\n' ' ' xs
--Should be called with the point maximum desired width as n
bestFieldWidth :: Int -> [String] -> Int
bestFieldWidth _ [] = error "bestFieldWidth: Empty List"
bestFieldWidth n xs
| n == 6 = 6
| 1 == (length (last input)) = n
| otherwise = (bestFieldWidth (n-1) xs)
where input = chunk n (unlines xs)
chunk :: Int -> [a] -> [[a]]
chunk n [] = []
chunk n xs = ys : chunk n zs
where (ys,zs) = splitAt n xs
itemsReplace :: Eq a => a -> a -> [a] -> [a]
itemsReplace _ _ [] = []
itemsReplace c r (x:xs)
| c == x = r:itemsReplace c r xs
| otherwise = x:itemsReplace c r xs
It seems that the condition length (last input) == length (head input) once false never goes true in subsequent calls to area, thus making this function always take the otherwise branch and keep calling itself indefinitely with the same values of xs and thus input.
Possible cause of this is that you use the lines function, which splits a string with newline characters, in a way not dependent on lineLength and inconsistent with your line-splitting in the rect function.
In answer to your side note, here is an excellent guide to debugging Haskell: http://cgi.cse.unsw.edu.au/~dons/blog/2007/11/14
There's also Debug.Trace, which allows you to insert print statements. It should of course only be used while debugging, because it makes your function have side effects.
http://hackage.haskell.org/packages/archive/base/latest/doc/html/Debug-Trace.html