I'm learning list operations in Haskell and now I'm trying out various list operations on Maybe list type. Currently, I have this implementation of sum of elements in list in Haskell
sum :: Num a => [a] -> a
sum [] = 0
sum (a:t) = a + sum t
Now I want to do the same thing but instead of returning the value, I want to return a Maybe type instead. And when the list given is empty it should return Nothing.
I've come up with this
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum (a:t) = fmap (a+) (sum t)
But the result of all non empty list given results in Nothing.
From what I understand, the list given will eventually pattern match with the empty list therefore returning Nothing.
How do I fix this so that it returns the expected value and of Maybe type. I can't figure out how to make it work recursively as the normal sum implementation above, so I guess there should be another way. Would prefer if only Prelude module is imported as I'm still trying to absorb stuff inside the Prelude module.
The problem is that your recursive function always uses the empty list as a base case, so your base case value is always Nothing. You only want to return Nothing if the "root" call takes an empty list. Otherwise, you want to use the singleton list as your base case.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum [x] = Just x
sum (a:t) = fmap (a+) (sum t)
This way, sum [] will never be reached by a recursive call; any non-empty list will hit the base case sum [x] first.
Another way to organize this is to use your original total function as a helper that sums non-empty lists only, and handle the empty list separately.
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = sum' xs
where sum' [] = Just 0
sum' (a:t) = fmap (a+) (sum' t)
Note that sum' can be called on an empty list, but only if it is originally called on a non-empty list.
As #chi points out, the helper function doesn't need to use Maybe at all; since it only sums non-empty lists, you can skip using fmap and sum the list normally; only the final result needs to be wrapped in Just:
sum :: Num a => [a] -> Maybe a
sum [] = Nothing
sum xs = Just (sum' xs)
where sum' [] = 0
sum' (a:t) = a + sum' t
Related
I am new to Haskell and I'm attempting a task in which the result should be the sum of the last two integers in a string.
I completely understand the overall addition part however it is the manipulation of the string recursively that I'm struggling with. To attempt the task I first 'flipped' the string with the last integer becoming the first for said string to be split after the nth term, in this case 2.
For example, with the given string 1,2,3,4,5,6,7. The result would be 13 as in 6+7=13.
sum' :: [a] -> [a]
sum' = foldl (\acc x -> x : acc) []
sum' :: [a] -> [a]
sum' [] = []
sum' xs = let h = splitAt 1 xs in h
sum' :: (Num a) => [a] -> a
sum' [] = 0
sum' (xs:x) = xs + sum' (x)
main :: IO()
main = do
print(sum'[1,2,3,4,5,6,7])
It is currently very messy and extremely inefficient (not to mention broken). Any help on the functions of haskell which will help me is greatly appreciated.
Working with the ends of lists is hard. My suggestion would be to reverse the list and take 2 elements off the front.
let a:b:_ = reverse [1,2,3,4,5,6,7] in a + b
By the way what you have here is not a String but a List of Int. While Strings are always lists in Haskell, not all Lists are Strings
You should recurse until only two elements are left in the list. So you implement two clauses for the normal behavior, and like some extra ones for the "corner cases".
The base case (1) is a list of two elements in which you need to sum up the elements; the recursive case (2) deals with a list with three or more elements, and recurses on the tail of the list:
sumlast2 :: Num a => [a] -> a
sumlast2 [x1, x2] = … -- (1)
sumlast2 (_:xs#(_:_:_)) = … -- (2)
-- … extra clauses for corner cases …
where you still need to fill in the … parts. In the second clause (2), xs is thus tail of the list: a list with all elements except the first one. You thus will need to define sumlast2 with three or more elements in terms of sumlast2.
I am trying to figure out how to create a recursive function that will find the largest element in the list and delete it then return the list. This is what i have so far but the problem is that every time i run it it returns the list without any of the values that are assigned to x.
deleteMax :: (Ord a) => [a] -> [a]
deleteMax [] = []
deleteMax [x] = []
deleteMax (x:y:xs)
|x == y = y: deleteMax xs
|x >= y = y: deleteMax xs
|x < y = x: deleteMax xs
This is not your answer
So you are a beginner and as such would like the simple solution of "how do I find the largest element in a list" followed by "how do I remove (one of the) largest element(s) in the list". This isn't that answer but it is me avoiding a long comment while also giving you something to come back to in 3 months.
The Lazy Way
One solution, which #n.m. and I were sparring about in comments, is to tie the knot (Googleable term). In this method you only need one logical pass over the list. In this case it is basically a trick to hide the pass that constructs the result list.
The idea is that during your pass over the list you do both tasks of 1. Compute the maximum element and 2. Compare with the maximum element and construct the list. There is nothing here that requires a monad but it can be easiest to see as part of a state monad:
deleteMaxState :: (Ord a) => [a] -> [a]
deleteMaxState [] = []
First we handle the base cases so we have a candidate 'maximum' (x) for our recursive operation.
deleteMaxState xs#(fstElem:_) =
let (r,(m,_)) = runState (go xs) (fstElem, notMax m)
notMax mx v = if (mx > v) then (v:) else id
go [] = return []
go (x:xs) =
do (curr,f) <- get
when (x > curr) (put (x,f))
f x <$> go xs
in r
In the loopwe track two values the first, curr, is the largest observed value by this point in our traversal of the list. The second value, f, is the trick - it is (a function including) the maximum value provided to the computation after the traversal has completed.
The magic is all here:
(r,(m,_)) = runState (go xs) (fstElem, m)
The left element of the result state (m,_) was our running maximum. Once the traversal ends we use that value - it becomes the right element (fstElem, m) and thus represents the maximum of the whole list.
We can use f to create thunks that populate portions of the list or just in-line construct our list as a bunch of unevaluated cons computations.
Making this one iota simpler, we can remove the higher-order function f and just have a number (untested):
deleteMaxState xs#(fstElem:_) =
let (r,(m,_)) = runState (go xs) (fstElem, m)
go [] = return []
go (x:xs) =
do (curr,theMax) <- get
when (x > curr) (put (x,theMax))
((if x >= theMax then Nothing else Just x) :) <$> go xs
in catMaybes r
Now we can see the second pass pretty explicitly not just as an unevaluated set of "some computation involving max, consed on the result" but as an actual pass via catMaybes.
The tying of the knot allows the programmer to write one logical traversal. This can be nice since it requires only one pattern match and recursive call per constructor of the list elements but at the cost of reasoning about evaluation order.
nFibbo :: [x] -> [x]
nFibbo x = x ++ sum x
I'm trying to setup a Fibonacci function and I want the input to be an integer array of indeterminate length and it's output to be an integer array of 1+ the length of the first.
I have tried just not typing it at all and running
nFibbo x = x ++ sum x
But that shows up with a different error "cannot construct the infinite type: a ~ [a]"
Well that's quite weird, since:
if x is an array [a], then sum x will be an a. The (++) :: [a] -> [a] -> [a] function takes two lists, not a list and an element.
You can however construct a list with one element, for instance using list syntax:
nFibbo :: Num x => [x] -> [x]
nFibbo x = x ++ [sum x] -- list with one element
Note that here you will add the sum of all previous elements as last element. Not the sum of the last two elements (like Fibonacci usually does).
You also need to add a Num x type constraint, otherwise the type of elements of the list is not per se a numerical type, and thus you can not calculate the sum of these numbers.
The full practice exam question is:
Using anonymous functions and mapping functions, define Haskell
functions which return the longest String in a list of Strings, e.g.
for [“qw”, “asd”,”fghj”, “kl”] the function should return “fghj”.
I tried doing this and keep failing and moving onto others, but I would really like to know how to tackle this. I have to use mapping functions and anonymous functions it seems, but I don't know how to write code to make each element check with each to find the highest one.
I know using a mapping function like "foldr" can make you perform repeating operations to each element and return one result, which is what we want to do with this question (check each String in the list of Strings for the longest, then return one string).
But with foldr I don't know how to use it to make checks between elments to see which is "longest"... Any help will be gladly appreciated.
So far I've just been testing if I can even use foldr to test the length of each element but it doesn't even work:
longstr :: [String] -> String
longstr lis = foldr (\n -> length n > 3) 0 lis
I'm quite new to haskell as this is a 3 month course and it's only been 1 month and we have a small exam coming up
I'd say they're looking for a simple solution:
longstr xs = foldr (\x acc -> if length x > length acc then x else acc) "" xs
foldr is like a loop that iterates on every element of the list xs. It receives 2 arguments: x is the element and acc (for accumulator) in this case is the longest string so far.
In the condition if the longest string so far is longer than the element we keep it, otherwise we change it.
Another idea:
Convert to a list of tuples: (length, string)
Take the maximum of that list (which is some pair).
Return the string of the pair returned by (2).
Haskell will compare pairs (a,b) lexicographically, so the pair returned by (2) will come from the string with largest length.
Now you just have to write a maximum function:
maximum :: Ord a => [a] -> a
and this can be written using foldr (or just plain recursion.)
To write the maximum function using recursion, fill in the blanks:
maximum [a] = ??? -- maximum of a single element
maximum (a:as) = ??? -- maximum of a value a and a list as (hint: use recursion)
The base case for maximum begins with a single element list since maximum [] doesn't make sense here.
You can map the list to a list of tuples, consisting of (length, string). Sort by length (largest first) and return the string of the first element.
https://stackoverflow.com/a/9157940/127059 has an answer as well.
Here's an example of building what you want from the bottom up.
maxBy :: Ord b => (a -> b) -> a -> a -> a
maxBy f x y = case compare (f x) (f y) of
LT -> y
_ -> x
maximumBy :: Ord b => (a -> b) -> [a] -> Maybe a
maximumBy _ [] = Nothing
maximumBy f l = Just . fst $ foldr1 (maxBy snd) pairs
where
pairs = map (\e -> (e, f e)) l
testData :: [String]
testData = ["qw", "asd", "fghj", "kl"]
test :: Maybe String
test = maximumBy length testData
main :: IO ()
main = print test
The language I'm using is a subset of Haskell called Core Haskell which does not allow the use of the built-in functions of Haskell. For example, if I were to create a function which counts the number of times that the item x appears in the list xs, then I would write:
count = \x ->
\xs -> if null xs
then 0
else if x == head xs
then 1 + count x(tail xs)
else count x(tail xs)
I'm trying to create a function which outputs a list xs with its duplicate values removed. E.g. remdups (7:7:7:4:5:7:4:4:[]) => (7:4:5:[])
can anyone offer any advice?
Thanks!
I'm guessing that you're a student, and this is a homework problem, so I'll give you part of the answer and let you finish it. In order to write remdups, it would be useful to have a function that tells us if a list contains an element. We can do that using recursion. When using recursion, start by asking yourself what the "base case", or simplest possible case is. Well, when the list is empty, then obviously the answer is False (no matter what the character is). So now, what if the list isn't empty? We can check if the first character in the list is a match. If it is, then we know that the answer is True. Otherwise, we need to check the rest of the list -- which we do by calling the function again.
elem _ [] = False
elem x (y:ys) = if x==y
then True
else elem x ys
The underscore (_) simply means "I'm not going to use this variable, so I won't even bother to give it a name." That can be written more succinctly as:
elem _ [] = False
elem x (y:ys) = x==y || elem x ys
Writing remdups is a little tricky, but I suspect your teacher gave you some hints. One way to approach it is to imagine we're partway through processing the list. We have part of the list that hasn't been processed yet, and part of the list that has been processed (and doesn't contain any duplicates). Suppose we had a function called remdupHelper, which takes those two arguments, called remaining and finished. It would look at the first character in remaining, and return a different result depending on whether or not that character is in finished. (That result could call remdupHelper recursively). Can you write remdupHelper?
remdupHelper = ???
Once you have remdupHelper, you're ready to write remdups. It just invokes remdupHelper in the initial condition, where none of the list has been processed yet:
remdups l = remdupHelper l [] -- '
This works with Ints:
removeDuplicates :: [Int] -> [Int]
removeDuplicates = foldr insertIfNotMember []
where
insertIfNotMember item list = if (notMember item list)
then item : list
else list
notMember :: Int -> [Int] -> Bool
notMember item [] = True
notMember item (x:xs)
| item == x = False
| otherwise = notMember item xs
How it works should be obvious. The only "tricky" part is that the type of foldr is:
(a -> b -> b) -> b -> [a] -> b
but in this case b unifies with [a], so it becomes:
(a -> [a] -> [a]) -> [a] -> [a] -> [a]
and therefore, you can pass the function insertIfNotMember, which is of type:
Int -> [Int] -> [Int] -- a unifies with Int