Haskell -- check last item of list - list

I need to check if last element of list is uppercase
For example "abc" -- False, "abC" -- True
That's what I tried
checkLast :: [a] -> Bool
checkLast [] = False
checkLast [x] = if isUpper x then True else False
checkLast (x:xs) = if isUpper last then True else False

Think recursively. checkLast (x:xs) is just checking checkLast xs:
checkLast :: [Char] -> Bool
checkLast [] = False
checkLast [x] = isUpper x
checkLast (x:xs) = checkLast xs
Note that since you are using isUpper to check strings, it makes more sense that the type should be [Char], not [a].

You can make use of recursion like the other answers demonstrate. But you can also use builtins to construct such a function.
Two relevant functions here are null :: [a] -> Bool which checks whether a list is empty, and last :: [a] -> a which obtains the last element.
So now we can construct a function:
import Data.Char(isUpper)
checkLast :: [Char] -> Bool
checkLast l = not (null l) && isUpper (last l)
So here we state that checkLast is True if the list l is not empty (not (null l)); and the last element is an uppercase character isUpper (last l).
This will probably be a bit faster than the recursive functions, since we only test the [] case once (in null). last checks only two cases: [x] and (x:xs) so we save on [] checks.
Of course these functions work with recursion, but it is sometimes useful to look for helper functions such that a function is almost self explaining: here the functions says: "A list l is checkLast if it is not empty, and the last element is an uppercase".

The simplest way to avoid explicit recursion, if you wish to do so, is probably to use a fold:
lastMay :: [a] -> Maybe a
lastMay = foldl' (\_ x -> Just x) Nothing
checkLast = maybe True isUpper . lastMay

A fixed version with comments:
import Data.Char (isUpper)
checkLast :: [Char] -> Bool -- it cannot be [a]: use of isUpper already limits possible type to [Char]
checkLast [] = False
checkLast [x] = isUpper x -- the if .. can be shorter
checkLast (x:xs) = checkLast xs -- drop first char and look at rest of string

You may also do as follows without any recursion
import Data.Char
checkLast :: String -> Bool
checkLast = (&&) <$> not . null <*> isUpper . head . reverse
The applicative operator, <*> is an ideal tool to feed a common parameter (the input string here) to two different functions like not . null and isUpper . head . reverse and then to make an operation (&&) on their result.
As per #dfeuer's comment I just would like to annex the following solution for a better performance. You don't need to import any other package than Data.Char
import Data.Char
checkLast :: String -> Bool
checkLast [] = False
checkLast cs = isUpper $ foldr1 seq cs

Related

Haskell function returns prefix

I am trying to create a function in haskell that takes a predicate and a list as arguments and returns the prefix of the list satisfying the predicate.
the test being:
p1tests = [myTakeWhile (/= ' ') "This is practice." == "This"]
I have this so far..
myTakeWhile :: (a-> Bool ) -> [a] -> [a]
myTakeWhile [] =[]
myTakeWhile (x:xs)=[] : map (x:) (myTakeWhile xs)
I receive errors saying except type
You need to work with both the predicate and the elements in the list. The function thus should look like:
myTakeWhile :: (a -> Bool) -> [a] -> [a]
myTakeWhile _ [] = []
myTakeWhile p (x:xs)
| p x = …
| otherwise = …
where the p x guard thus covers the case where the predicate is satisfied for the first item of the list, and the otherwise is not.
In case the predicate is satisfied, we have to yield x and recurse on the tail of the list. I keep filling in … as an exercise.

nub not compiling when checking a list for duplicates

Working on a sudoku inspired assignment and I need to implement a function that checks if a Block Cell has no repeated elements in it (to check if its a valid solution to the puzzle).
okBlock :: Block Cell -> Bool
okBlock b = okList $ filter (/= Nothing) b
where
okList :: [a]-> Bool
okList list
| (length list) == (length (nub list)) = True
| otherwise = False
Block a = [a]
Cell = [Maybe Int]
Haskell complains saying No instance for (Eq a) arising from a use of "==" Possible fix: add (Eq a) to the context of the type signature for okList...
Adding Eq a to the type signature does not help. I have tried the function in the terminal and it works fine for for lists, and for lists of lists (i.e the type I am feeding it in the function).
What am I missing here?
Well you can only filter out duplicates, if there is a way to check whether two values are duplicates. If we look at the type signature for nub, we see:
nub :: Eq a => [a] -> [a]
So that means that in order to filter out duplicates in a list of as, we need a to be an instance of the Eq class. We can thus simply forward the type constraint further in the signatures of the functions:
okBlock :: Block Cell -> Bool
okBlock b = okList $ filter (/= Nothing) b
where
okList :: Eq => [a] -> Bool
okList list
| (length list) == (length (nub list)) = True
| otherwise = False
We do not need to specify that Cell is an instance of Eq because:
Int is an instance of Eq;
if a is an instance of Eq, so is Maybe a, so Maybe Int is an instance of Eq; and
if a is an instance of Eq, so is [a], so [Maybe Int] is an instance of Eq.
That being said we can do some syntactical improvements of the code:
there is no need to work with guards if you simply return the result of the guard True and False, and
you can use an eta reduction and omit the b in okBlock.
you don't need parentheses around function application (unless to feed to result straight to another, non-infix function).
This gives us:
okBlock :: Block Cell -> Bool
okBlock = okList . filter (/= Nothing)
where
okList :: Eq => [a] -> Bool
okList list = length list == length (nub list)
A final note is that usually you do not have to specify a type signature. In that case Haskell will aim to dervice the most generic type signature. So you can write:
okBlock = okList . filter (/= Nothing)
where
okList list = length list == length (nub list)
Now okBlock will have type:
Prelude Data.List> :t okBlock
okBlock :: Eq a => [Maybe a] -> Bool
Three points that are too big to make in a comment.
nub is horribly slow
nub takes O(n^2) time to process a list of length n. Unless you know the list is very short, this is the wrong function to use to remove duplicates from a list. Adding a bit more information about what sort of thing you're working with allows more efficient nubbing. The simplest, and probably most general, approach that isn't absolutely wretched is to use an Ord constraint:
import qualified Data.Set as S
nubOrd :: Ord a => [a] -> [a]
nubOrd = go S.empty where
go _seen [] = []
go seen (a : as)
| a `S.member` seen = go seen as
| otherwise = go (S.insert a seen) as
length is wasteful
Suppose I write
sameLength :: [a] -> [b] -> Bool
sameLength xs ys = length xs == length ys
(which uses the approach you did). Now imagine I calculate
sameLength [1..16] [1..2^100]
How long will that take? Calculating length [1..16] will take nanoseconds. Calculating length [1..2^100] will probably take billions of years using current hardware. Whoops. What's the right way? Pattern match!
sameLength [] [] = True
sameLength (_ : xs) (_ : ys) = sameLength xs ys
sameLength _ _ = False
Nubbing isn't the right solution to this problem
Suppose I ask noDuplicates (1 : [1,2..]). Obviously, there's a duplicate, right at the beginning. But if I use sameLength and nub to check, I will never get an answer. It will keep building the nubbed list and comparing it to the original list until the seen becomes so large it exhausts your computer's memory. How can you fix that? By directly calculating what you need:
noDuplicates = go S.empty where
go _seen [] = True
go seen (x : xs)
| x `S.member` seen = False
| otherwise = go (S.insert x seen) xs
Now the program will conclude that there's a duplicate the moment it sees the second 1.

Is there a function that takes a list and returns a list of duplicate elements in that list?

Is there a Haskell function that takes a list and returns a list of duplicates/redundant elements in that list?
I'm aware of the the nub and nubBy functions, but they remove the duplicates; I would like to keep the dupes and collects them in a list.
The simplest way to do this, which is extremely inefficient, is to use nub and \\:
import Data.List (nub, (\\))
getDups :: Eq a => [a] -> [a]
getDups xs = xs \\ nub xs
If you can live with an Ord constraint, everything gets much nicer:
import Data.Set (member, empty, insert)
getDups :: Ord a => [a] -> [a]
getDups xs = foldr go (const []) xs empty
where
go x cont seen
| member x seen = x : r seen
| otherwise = r (insert x seen)
I wrote these functions which seems to work well.
The first one return the list of duplicates element in a list with a basic equlity test (==)
duplicate :: Eq a => [a] -> [a]
duplicate [] = []
duplicate (x:xs)
| null pres = duplicate abs
| otherwise = x:pres++duplicate abs
where (pres,abs) = partition (x ==) xs
The second one make the same job by providing a equality test function (like nubBy)
duplicateBy :: (a -> a -> Bool) -> [a] -> [a]
duplicateBy eq [] = []
duplicateBy eq (x:xs)
| null pres = duplicateBy eq abs
| otherwise = x:pres++duplicateBy eq abs
where (pres,abs) = partition (eq x) xs
Is there a Haskell function that takes a list and returns a list of duplicates/redundant elements in that list?
You can write such a function yourself easily enough. Use a helper function that takes two list arguments, the first one of which being the list whose dupes are sought; walk along that list and accumulate the dupes in the second argument; finally, return the latter when the first argument is the empty list.
dupes l = dupes' l []
where
dupes' [] ls = ls
dupes' (x:xs) ls
| not (x `elem` ls) && x `elem` xs = dupes' xs (x:ls)
| otherwise = dupes' xs ls
Test:
λ> dupes [1,2,3,3,2,2,3,4]
[3,2]
Be aware that the asymptotic time complexity is as bad as that of nub, though: O(n^2). If you want better asymptotics, you'll need an Ord class constraint.
If you are happy with an Ord constraint you can use group from Data.List:
getDups :: Ord a => [a] -> [a]
getDups = concatMap (drop 1) . group . sort

Replace an element in a list only once - Haskell

I want to replace an element in a list with a new value only at first time occurrence.
I wrote the code below but using it, all the matched elements will change.
replaceX :: [Int] -> Int -> Int -> [Int]
replaceX items old new = map check items where
check item | item == old = new
| otherwise = item
How can I modify the code so that the changing only happen at first matched item?
Thanks for helping!
The point is that map and f (check in your example) only communicate regarding how to transform individual elements. They don't communicate about how far down the list to transform elements: map always carries on all the way to the end.
map :: (a -> b) -> [a] -> [b]
map _ [] = []
map f (x:xs) = f x : map f xs
Let's write a new version of map --- I'll call it mapOnce because I can't think of a better name.
mapOnce :: (a -> Maybe a) -> [a] -> [a]
There are two things to note about this type signature:
Because we may stop applying f part-way down the list, the input list and the output list must have the same type. (With map, because the entire list will always be mapped, the type can change.)
The type of f hasn't changed to a -> a, but to a -> Maybe a.
Nothing will mean "leave this element unchanged, continue down the list"
Just y will mean "change this element, and leave the remaining elements unaltered"
So:
mapOnce _ [] = []
mapOnce f (x:xs) = case f x of
Nothing -> x : mapOnce f xs
Just y -> y : xs
Your example is now:
replaceX :: [Int] -> Int -> Int -> [Int]
replaceX items old new = mapOnce check items where
check item | item == old = Just new
| otherwise = Nothing
You can easily write this as a recursive iteration like so:
rep :: Eq a => [a] -> a -> a -> [a]
rep items old new = rep' items
where rep' (x:xs) | x == old = new : xs
| otherwise = x : rep' xs
rep' [] = []
A direct implementation would be
rep :: Eq a => a -> a -> [a] -> [a]
rep _ _ [] = []
rep a b (x:xs) = if x == a then b:xs else x:rep a b xs
I like list as last argument to do something like
myRep = rep 3 5 . rep 7 8 . rep 9 1
An alternative using the Lens library.
>import Control.Lens
>import Control.Applicative
>_find :: (a -> Bool) -> Simple Traversal [a] a
>_find _ _ [] = pure []
>_find pred f (a:as) = if pred a
> then (: as) <$> f a
> else (a:) <$> (_find pred f as)
This function takes a (a -> Bool) which is a function that should return True on an type 'a' that you wan to modify.
If the first number greater then 5 needs to be doubled then we could write:
>over (_find (>5)) (*2) [4, 5, 3, 2, 20, 0, 8]
[4,5,3,2,40,0,8]
The great thing about lens is that you can combine them together by composing them (.). So if we want to zero the first number <100 in the 2th sub list we could:
>over ((element 1).(_find (<100))) (const 0) [[1,2,99],[101,456,50,80,4],[1,2,3,4]]
[[1,2,99],[101,456,0,80,4],[1,2,3,4]]
To be blunt, I don't like most of the answers so far. dave4420 presents some nice insights on map that I second, but I also don't like his solution.
Why don't I like those answers? Because you should be learning to solve problems like these by breaking them down into smaller problems that can be solved by simpler functions, preferably library functions. In this case, the library is Data.List, and the function is break:
break, applied to a predicate p and a list xs, returns a tuple where first element is longest prefix (possibly empty) of xs of elements that do not satisfy p and second element is the remainder of the list.
Armed with that, we can attack the problem like this:
Split the list into two pieces: all the elements before the first occurence of old, and the rest.
The "rest" list will either be empty, or its first element will be the first occurrence of old. Both of these cases are easy to handle.
So we have this solution:
import Data.List (break)
replaceX :: Eq a => a -> a -> [a] -> [a]
replaceX old new xs = beforeOld ++ replaceFirst oldAndRest
where (beforeOld, oldAndRest) = break (==old) xs
replaceFirst [] = []
replaceFirst (_:rest) = new:rest
Example:
*Main> replaceX 5 7 ([1..7] ++ [1..7])
[1,2,3,4,7,6,7,1,2,3,4,5,6,7]
So my advice to you:
Learn how to import libraries.
Study library documentation and learn standard functions. Data.List is a great place to start.
Try to use those library functions as much as you can.
As a self study exercise, you can pick some of the standard functions from Data.List and write your own versions of them.
When you run into a problem that can't be solved with a combination of library functions, try to invent your own generic function that would be useful.
EDIT: I just realized that break is actually a Prelude function, and doesn't need to be imported. Still, Data.List is one of the best libraries to study.
Maybe not the fastest solution, but easy to understand:
rep xs x y =
let (left, (_ : right)) = break (== x) xs
in left ++ [y] ++ right
[Edit]
As Dave commented, this will fail if x is not in the list. A safe version would be:
rep xs x y =
let (left, right) = break (== x) xs
in left ++ [y] ++ drop 1 right
[Edit]
Arrgh!!!
rep xs x y = left ++ r right where
(left, right) = break (== x) xs
r (_:rs) = y:rs
r [] = []
replaceValue :: Int -> Int -> [Int] -> [Int]
replaceValue a b (x:xs)
|(a == x) = [b] ++ xs
|otherwise = [x] ++ replaceValue a b xs
Here's an imperative way to do it, using State Monad:
import Control.Monad.State
replaceOnce :: Eq a => a -> a -> [a] -> [a]
replaceOnce old new items = flip evalState False $ do
forM items $ \item -> do
replacedBefore <- get
if item == old && not replacedBefore
then do
put True
return new
else
return old

Haskell custom isordered function to check a list of integers

I'm trying to write a Haskell function that checks if a list of integers is in order without using any of the already existing functions to order or check the order of the list. I have written the following code but I do not understand why it does not work. I get the error:
No instance for (Ord integer)
arising from a use of `<='
In the expression: x <= (head xs)
I don't understand what this means. Is there a different way that I should be writing this function? Here is my code so far.
isordered :: [integer] -> Bool
isordered [] = True
isordered (x:[]) = True
isordered (x:xs)|x <= (head xs) = isordered xs
|otherwise = False
Thanks in advance!!!
In Haskell type names start with capital letters and type variables start with lower case letters. So if you write integer, that's a type variable. So your type is the same as [a] -> Bool, i.e. you take a list of anything and return a Bool. So since there's no restriction on what type of item might be in the list, you're not allowed to use <= on it.
To fix this you can either just change it to Integer, which is what you wanted, or add an Ord constraint like this: Ord a => [a] -> Bool. The latter will make your function work with any type that implements the Ord typeclass (which provides the comparison operators such as <=).
What exactly counts as "already existing function"?
isordered xs = all (uncurry (<=)) $ zip xs (tail xs)
More low-level is
isordered (x:y:zs) = x <= y && isordered (y:zs)
isordered _ = True
Another way for doing it using guards:
isOrdered :: Ord a => [a] -> Bool
isOrdered (x:y:xs) | x<=y = isOrdered (y:xs)
| otherwise = False
isOrdered _ = True