Haskell: Using multiple let and return a value after the do block inside a function - haskell

As the title says, i want to return a value after the do block.
Example: Writing a function that inserts a variable at a given position in an array:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = do
let before = take n xs
let after = drop n xs
let merged = before ++ [x] ++ after
in merged
For example:
insertAt 'x' 3 "Aleander" => "Alexander"
Anyway, when using a single let call, one could return a value using the in keyword, but with the multiple calls of let as in the example i get the error:
error: parse error on input `in'
I know i could do the whole thing in a single let usage, but i want to know how to deal with multiple let calls :)
Thanks for the help!

Please do not use a do expression. do expressions are snytactical sugar for expressions with binds. Yes a list is an instance of Monad, but you use it not in the correct way.
You can here define your lets in a block like:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs =
let before = take n xs
after = drop n xs
merged = before ++ [x] ++ after
in merged
But it might be more elegant to use splitAt :: Int -> [a] -> ([a], [a]), like:
insertAt :: a -> Int -> [a] -> [a]
insertAt x n xs = let (hs,ts) = splitAt n xs in hs ++ x : ts

If you want to use the list monad, though, you can write
insertAt x n ys = do
(i, y) <- zip [0..] ys
if i == n then [x, y] else [y]
This works by "numbering" each element of the input list. Normally, you just return each element as you find it (remember, return x == [x] in the list monad). But at position n, you want to "sneak in" x before the current element of the existing list. You do that by providing the list [x,y] instead of simply [y].
insertAt 'x' 3 "Aleander" essentially becomes concat ["A", "l", "e", "xa", "n", "d", "e", "r"].
Drawback: it won't append 'x' to the output, regardless of what n you supply, so this may be more of a demonstration of the list monad than a solution to your actual problem. One simple fix is to special case n == 0, then insert x after the n the element. This lets you append if n == length ys, but not n > length ys:
insertAt x n ys = if n == 0 then x:ys else do
(i, y) <- zip [1..] ys -- Note the increase in indices
if i == n then [y, x] else [y]

Related

create a function ved that will only remove the last occurrence of the largest item in the list using recursion

You must use recursion to define rmax2 and you must do so from “scratch”. That is, other than the cons operator, head, tail, and comparisons, you should not use any functions from the Haskell library.
I created a function that removes all instances of the largest item, using list comprehension. How do I remove the last instance of the largest number using recursion?
ved :: Ord a => [a] -> [a]
ved [] =[]
ved as = [ a | a <- as, m /= a ]
where m= maximum as
An easy way to split the problem into two easier subproblems consists in:
get the position index of the rightmost maximum value
write a general purpose function del that eliminates the element of a list at a given position. This does not require an Ord constraint.
If we were permitted to use regular library functions, ved could be written like this:
ved0 :: Ord a => [a] -> [a]
ved0 [] = []
ved0 (x:xs) =
let
(maxVal,maxPos) = maximum (zip (x:xs) [0..])
del k ys = let (ys0,ys1) = splitAt k ys in (ys0 ++ tail ys1)
in
del maxPos (x:xs)
where the pairs produced by zip are lexicographically ordered, thus ensuring the rightmost maximum gets picked.
We need to replace the library functions by manual recursion.
Regarding step 1, that is finding the position of the rightmost maximum, as is commonly done, we can use a recursive stepping function and a wrapper above it.
The recursive step function takes as arguments the whole context of the computation, that is:
current candidate for maximum value, mxv
current rightmost position of maximum value, mxp
current depth into the original list, d
rest of original list, xs
and it returns a pair: (currentMaxValue, currentMaxPos)
-- recursive stepping function:
findMax :: Ord a => a -> Int -> Int -> [a] -> (a, Int)
findMax mxv mxp d [] = (mxv,mxp)
findMax mxv mxp d (x:xs) = if (x >= mxv) then (findMax x d (d+1) xs)
else (findMax mxv mxp (d+1) xs)
-- top wrapper:
lastMaxPos :: Ord a => [a] -> Int
lastMaxPos [] = (-1)
lastMaxPos (x:xs) = snd (findMax x 0 1 xs)
Step 2, eliminating the list element at position k, can be handled in very similar fashion:
-- recursive stepping function:
del1 :: Int -> Int -> [a] -> [a]
del1 k d [] = []
del1 k d (x:xs) = if (d==k) then xs else x : del1 k (d+1) xs
-- top wrapper:
del :: Int -> [a] -> [a]
del k xs = del1 k 0 xs
Putting it all together:
We are now able to write our final recursion-based version of ved. For simplicity, we inline the content of wrapper functions instead of calling them.
-- ensure we're only using authorized functionality:
{-# LANGUAGE NoImplicitPrelude #-}
import Prelude (Ord, Eq, (==), (>=), (+), ($), head, tail,
IO, putStrLn, show, (++)) -- for testing only
ved :: Ord a => [a] -> [a]
ved [] = []
ved (x:xs) =
let
findMax mxv mxp d [] = (mxv,mxp)
findMax mxv mxp d (y:ys) = if (y >= mxv) then (findMax y d (d+1) ys)
else (findMax mxv mxp (d+1) ys)
(maxVal,maxPos) = findMax x 0 1 xs
del1 k d (y:ys) = if (d==k) then ys else y : del1 k (d+1) ys
del1 k d [] = []
in
del1 maxPos 0 (x:xs)
main :: IO ()
main = do
let xs = [1,2,3,7,3,2,1,7,3,5,7,5,4,3]
res = ved xs
putStrLn $ "input=" ++ (show xs) ++ "\n" ++ " res=" ++ (show res)
If you are strictly required to use recursion, you can use 2 helper functions: One to reverse the list and the second to remove the first largest while reversing the reversed list.
This result in a list where the last occurrence of the largest element is removed.
We also use a boolean flag to make sure we don't remove more than one element.
This is ugly code and I really don't like it. A way to make things cleaner would be to move the reversal of the list to a helper function outside of the current function so that there is only one helper function to the main function. Another way is to use the built-in reverse function and use recursion only for the removal.
removeLastLargest :: Ord a => [a] -> [a]
removeLastLargest xs = go (maximum xs) [] xs where
go n xs [] = go' n True [] xs
go n xs (y:ys) = go n (y:xs) ys
go' n f xs [] = xs
go' n f xs (y:ys)
| f && y == n = go' n False xs ys
| otherwise = go' n f (y:xs) ys
Borrowing the implementation of dropWhileEnd from Hackage, we can implement a helper function splitWhileEnd:
splitWhileEnd :: (a -> Bool) -> [a] -> ([a], [a])
splitWhileEnd p = foldr (\x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)) ([],[])
splitWhileEnd splits a list according to a predictor from the end. For example:
ghci> xs = [1,2,3,4,3,2,4,3,2]
ghci> splitWhileEnd (< maximum xs) xs
([1,2,3,4,3,2,4],[3,2])
With this helper function, you can write ven as:
ven :: Ord a => [a] -> [a]
ven xs =
let (x, y) = splitWhileEnd (< maximum xs) xs
in init x ++ y
ghci> ven xs
[1,2,3,4,3,2,3,2]
For your case, you can refactor splitWhileEnd as:
fun p = \x (xs, ys) -> if p x && null xs then ([], x:ys) else (x:xs, ys)
splitWhileEnd' p [] = ([], [])
splitWhileEnd' p (x : xs) = fun p x (splitWhileEnd' p xs)
ven' xs = let (x, y) = splitWhileEnd' (< maximum xs) xs in init x ++ y
If init and ++ are not allowed, you can implement them manually. It's easy!
BTW, I guess this may be your homework for Haskell course. I think it's ridiculous if your teacher gives the limitations. Who is programming from scratch nowadays?
Anyway, you can always work around this kind of limitations by reimplementing the built-in function manually. Good luck!

Get positions of elements in list of strings in Haskell

my title might be a bit off and i'll try to explain a bit better what i'm trying to achieve.
Basically let's say i have a list:
["1234x4","253x4",2839",2845"]
Now i'd like to add all the positions of the strings which contain element 5 to a new list. On a current example the result list would be:
[1,3]
For that i've done similar function for elem:
myElem [] _ = False
myElem [x] number =
if (firstCheck x) then if digitToInt(x) == number then True else False else False
myElem (x:xs) number =
if (firstCheck x) then (if digitToInt(x) == number then True else myElem xs number) else myElem xs number
where firstCheck x checks that the checked element isn't 'x' or '#'
Now in my current function i get the first element position which contains the element, however my head is stuck around on how to get the full list:
findBlock (x:xs) number arv =
if myElem x number then arv else findBlock xs number arv+1
Where arv is 0 and number is the number i'm looking for.
For example on input:
findBlock ["1234x4","253x4",2839",2845"] 5 0
The result would be 1
Any help would be appreciated.
The function you want already exists in the Data.List module, by the name of findIndices. You can simply use (elem '5') as the predicate.
http://hackage.haskell.org/package/base-4.8.1.0/docs/Data-List.html#v:findIndices
If, for some reason, you're not allowed to use the built-in one, it comes with a very pretty definition (although the one actually used has a more complicated, more efficient one):
findIndices p xs = [ i | (x,i) <- zip xs [0..], p x]
By the way, I found this function by searching Hoogle for the type [a] -> (a -> Bool) -> [Int], which (modulo parameter ordering) is obviously the type such a function must have. The best way to find out of Haskell has something is to think about the type it would need to have and search Hoogle or Hayoo for the type. Hoogle is better IMO because it does slightly fuzzy matching on the type; e.g. Hayoo wouldn't find the function here by the type I've given, because it take the arguments in the reverse order.
An implementation of findIndices, for instructional purposes:
findIndices ok list = f list 0 where
f [] _ = []
f (x:xs) ix
| ok x = ix : f xs (ix+1)
| otherwise = f xs (ix+1)
Use it like findIndices (elem '5') my_list_o_strings
You're trying to work your way through a list, keeping track of where you are in the list. The simplest function for doing this is
mapWithIndex :: (Int -> a -> b) -> [a] -> [b]
mapWithIndex = mwi 0 where
mwi i _f [] = i `seq` []
mwi i f (x:xs) = i `seq` f i x : mwi (i+1) f xs
This takes a function and a list, and applies the function to each index and element. So
mapWithIndex (\i x -> (i, x)) ['a', 'b', 'c'] =
[(0,'a'), (1,'b'),(2,'c')]
Once you've done that, you can filter the list to get just the pairs you want:
filter (elem '5' . snd)
and then map fst over it to get the list of indices.
A more integrated approach is to use foldrWithIndex.
foldrWithIndex :: (Int -> a -> b -> b) -> b -> [a] -> b
foldrWithIndex = fis 0 where
fis i _c n [] = i `seq` n
fis i c n (x:xs) = i `seq` c i x (fis (i+1) c n xs)
This lets you do everything in one step.
It turns out that you can implement foldrWithIndex using foldr pretty neatly, which makes it available for any Foldable container:
foldrWithIndex :: (Foldable f, Integral i) =>
(i -> a -> b -> b) -> b -> f a -> b
foldrWithIndex c n xs = foldr go (`seq` n) xs 0 where
go x r i = i `seq` c i x (r (i + 1))
Anyway,
findIndices p = foldrWithIndex go [] where
go i x r | p x = i : r
| otherwise = r

Find the K'th element of a list using foldr

I try to implement own safe search element by index in list.
I think, that my function have to have this signature:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
iteration = undefined
init_val = undefined
I have problem with implementation of iteration. I think, that it has to look like this:
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
where
iteration :: a -> (Int -> [a]) -> Int -> a
iteration x g 0 = []
iteration x g n = x (n - 1)
init_val :: Int -> a
init_val = const 0
But It has to many errors. My intuition about haskell is wrong.
you have
safe_search :: [a] -> Int -> Maybe a
safe_search xs n = foldr iteration init_val xs n
if null xs holds, foldr iteration init_val [] => init_val, so
init_val n
must make sense. Nothing to return, so
= Nothing
is all we can do here, to fit the return type.
So init_val is a function, :: Int -> Maybe a. By the definition of foldr, this is also what the "recursive" argument to the combining function is, "coming from the right":
iteration x r
but then this call must also return just such a function itself (again, by the definition of foldr, foldr f z [a,b,c,...,n] == f a (f b (f c (...(f n z)...))), f :: a -> b -> b i.e. it must return a value of the same type as it gets in its 2nd argument ), so
n | n==0 = Just x
That was easy, 0-th element is the one at hand, x; what if n > 0?
| n>0 = ... (n-1)
Right? Just one more step left for you to do on your own... :) It's not x (the list's element) that goes on the dots there; it must be a function. We've already received such a function, as an argument...
To see what's going on here, it might help to check the case when the input is a one-element list, first,
safe_search [x] n = foldr iteration init_val [x] n
= iteration x init_val n
and with two elements,
[x1, x2] n = iteration x1 (iteration x2 init_val) n
-- iteration x r n
Hope it is clear now.
edit: So, this resembles the usual foldr-based implementation of zip fused with the descending enumeration from n down, indeed encoding the more higher-level definition of
foo xs n = ($ zip xs [n,n-1..]) $
dropWhile ((>0) . snd) >>>
map fst >>>
take 1 >>> listToMaybe
= drop n >>> take 1 >>> listToMaybe $ xs
Think about a few things.
What type should init_val have?
What do you need to do with g? g is the trickiest part of this code. If you've ever learned about continuation-passing style, you should probably think of both init_val and g as continuations.
What does x represent? What will you need to do with it?
I wrote up an explanation some time ago about how the definition of foldl in terms of foldr works. You may find it helpful.
I suggest to use standard foldr pattern, because it is easier to read and understand the code, when you use standard functions:
foldr has the type foldr :: (a -> b -> b) -> [a] -> b -> [b],
where third argument b is the accumulator acc for elements of your list [a].
You need to stop adding elements of your list [a] to acc after you've added desired element of your list. Then you take head of the resulting list [b] and thus get desired element of the list [a].
To get n'th element of the list xs, you need to add length xs - n elements of xs to the accumulator acc, counting from the end of the list.
But where to use an iterator if we want to use the standard foldr function to improve the readability of our code? We can use it in our accumulator, representing it as a tuple (acc, iterator). We subtract 1 from the iterator each turn we add element from our initial list xs to the acc and stop to add elements of xs to the acc when our iterator is equal 0.
Then we apply head . fst to the result of our foldr function to get the desired element of the initial list xs and wrap it with Just constructor.
Of course, if length - 1 of our initial list xs is less than the index of desired element n, the result of the whole function safeSearch will be Nothing.
Here is the code of the function safeSearch:
safeSearch :: Int -> [a] -> Maybe a
safeSearch n xs
| (length xs - 1) < n = Nothing
| otherwise = return $ findElem n' xs
where findElem num =
head .
fst .
foldr (\x (acc,iterator) ->
if iterator /= 0
then (x : acc,iterator - 1)
else (acc,iterator))
([],num)
n' = length xs - n

What's an efficient way to pluck an element out of a list and return the element, and rest of list in a tuple?

This seems to be a very common operation but I can't find it in hoogle for some reason. Either way, it's an interesting thought exercise. My naive implementation:
pluckL :: [a] -> Int -> Maybe ( a, [a] )
pluckL xs idx = if idx < length xs then Just $ pluck' xs idx else Nothing
where
pluck' l n = let subl = drop n l in ( head subl, rest l n ++ tail subl )
rest l n = reverse $ drop ( length l - n ) $ reverse l
My main gripe is that I'm flipping the list too many times, so I'm looking for a creative way where you can traverse the list once and generate the tuple.
There will never be an efficient way. But there can at least be a pretty way:
pluckL xs i = case splitAt i xs of
(b, v:e) -> Just (v, b ++ e)
_ -> Nothing
You can get by with one fewer reverse and fewer operations on the list if you use an accumulator:
pluckL :: [a] -> Int -> Maybe (a, [a])
pluckL xs idx = pluck xs idx [] where
pluck (x:xs) 0 acc = Just $ ( x, (reverse acc) ++ xs )
pluck (x:xs) i acc = pluck xs (i-1) (x:acc)
pluck [] i acc = Nothing
You can use elem to check if the elem is in the list or not, then depending of the result return Nothing or use delete x to remove x from the list, as follow for example,
pluckL :: Eq a => [a] -> a -> Maybe (a, [a])
pluckL xs0 x =
if (x `elem` xs0)
then Just (x, xs)
else Nothing
where xs = delete x xs0

can you get a count on matches in a list comprehension (trying to insertionSort on a qsort after threshold)

I come from a C++ background so I'm not sure if I'm even going about this properly. But what I'm trying to do is write up quick sort but fallback to insertion sort if the length of a list is less than a certain threshold. So far I have this code:
insertionSort :: (Ord a) => [a] -> [a]
insertionSort [] = []
insertionSort (x:xs) = insert x (insertionSort xs)
quickSort :: (Ord a) => [a] -> [a]
quickSort x = qsHelper x (length x)
qsHelper :: (Ord a) => [a] -> Int -> [a]
qsHelper [] _ = []
qsHelper (x:xs) n
| n <= 10 = insertionSort xs
| otherwise = qsHelper before (length before) ++ [x] ++ qsHelper after (length after)
where
before = [a | a <- xs, a < x]
after = [a | a <- xs, a >= x]
Now what I'm concerned about is calculating the length of each list every time. I don't fully understand how Haskell optimizes things or the complete effects of lazy evaluation on code like the above. But it seems like calculating the length of the list for each before and after list comprehension is not a good thing? Is there a way for you to extract the number of matches that occurred in a list comprehension while performing the list comprehension?
I.e. if we had [x | x <- [1,2,3,4,5], x > 3] (which results in [4,5]) could I get the count of [4,5] without using a call to length?
Thanks for any help/explanations!
Short answer: no.
Less short answer: yes, you can fake it. import Data.Monoid, then
| otherwise = qsHelper before lenBefore ++ [x] ++ qsHelper after lenAfter
where
(before, Sum lenBefore) = mconcat [([a], Sum 1) | a <- xs, a < x]
(after, Sum lenAfter) = mconcat [([a], Sum 1) | a <- xs, a >= x]
Better answer: you don't want to.
Common reasons to avoid length include:
its running time is O(N)
but it costs us O(N) to build the list anyway
it forces the list spine to be strict
but we're sorting the list: we have to (at least partially) evaluate each element in order to know which is the minimum; the list spine is already forced to be strict
if you don't care how long the list is, just whether it's shorter/longer than another list or a threshold, length is wasteful: it will walk all the way to the end of the list regardless
BINGO
isLongerThan :: Int -> [a] -> Bool
isLongerThan _ [] = False
isLongerThan 0 _ = True
isLongerThan n (_:xs) = isLongerThan (n-1) xs
quickSort :: (Ord a) => [a] -> [a]
quickSort [] = []
quickSort (x:xs)
| not (isLongerThan 10 (x:xs)) = insertionSort xs
| otherwise = quickSort before ++ [x] ++ quickSort after
where
before = [a | a <- xs, a < x]
after = [a | a <- xs, a >= x]
The real inefficiency here though is in before and after. They both step through the entire list, comparing each element against x. So we are stepping through xs twice, and comparing each element against x twice. We only have to do it once.
(before, after) = partition (< x) xs
partition is in Data.List.
No, there is no way to use list comprehensions to simultaneously do a filter and count the number of found elements. But if you are worried about this performance hit, you should not be using the list comprehensions the way you are in the first place: You are filtering the list twice, hence applying the predicate <x and its negation to each element. A better variant would be
(before, after) = partition (< x) xs
Starting from that it is not hard to write a function
partitionAndCount :: (a -> Bool) -> [a] -> (([a],Int), ([a],Int))
that simultaneously partitions and counts the list and counts the elements in each of the returned list:
((before, lengthBefore), (after, lengthAfter)) = partitionAndCount (< x) xs
Here is a possible implementation (with a slightly reordered type):
{-# LANGUAGE BangPatterns #-}
import Control.Arrow
partitionAndCount :: (a -> Bool) -> [a] -> (([a], [a]), (Int, Int))
partitionAndCount p = go 0 0
where go !c1 !c2 [] = (([],[]),(c1,c2))
go !c1 !c2 (x:xs) = if p x
then first (first (x:)) (go (c1 + 1) c2 xs)
else first (second (x:)) (go c1 (c2 + 1) xs)
And here you can see it in action:
*Main> partitionAndCount (>=4) [1,2,3,4,5,3,4,5]
(([4,5,4,5],[1,2,3,3]),(4,4))

Resources