Shortening a String Haskell - haskell

How do you shorten a string in Haskell with a given number.
Say:
comp :: String -> String
short :: String -> String
chomp (x:xs) = (x : takeWhile (==x) xs)
using comp I want to select a run of repeated characters from the start of a string, with
the run comprising at most nine characters.
For example:
short "aaaavvvdd"
would output "aaaa"
and short "dddddddddd"
outputs "ddddddddd".
I know I need take but am not sure how to put that into the code.
i've got this far but it doesn't work
short x:xs | length(short x:xs) >9 = take(9)
| otherwise = comp

The Quick Answer
import Data.List
short [] = []
short x = (take 9 . head . group) x
This will give you output that matches your desired output.
That is,
*> short "aaaavvvdd"
"aaaa"
*> short "dddddddddd"
"ddddddddd"
Step by Step Development
Use "group" to separate the items
This solution depends on the "group" function in the Data.List library. We begin with the definition:
short x = group x
This gives us:
*> short "aaaavvvddd"
["aaaa","vvv","ddd"]
Use "head" to return only the first element
Once we have the the elements in a list, we want only the first item of the list. We achieve this using "head":
short x = (head . group) x
"." is the Haskell function for function composition. It's the same as:
short x = head (group x)
or
short x = head $ group x
This will give us:
*> short "aaaavvvdd"
"aaaa"
*> short "dddddddddddddd"
"dddddddddddddd"
Use "take" to get the first nine characters
We finish the program by taking only the first nine characters of this result, and end up with our final function. To do this, we use the "take" function from the prelude:
short x = (take 9 . head . group) x
We now have the result that we wanted, but with one minor problem.
Add another case to eliminate the error
Note that using our current definition on the empty list causes an error,
*> short "aaaavvvddd"
"aaaa"
*> short ""
"*** Exception: Prelude.head: empty list
Because "head" is undefined on the empty list, we need to handle another case: the empty list. Now we have:
short [] = []
short x = (take 9 . head . group) x
This is our "final answer".

Here is another version:
short xs = take 9 $ takeWhile (== head xs) xs
So we take from the list as long as the content equals the head of list (which is the first char of the string). Then we use take to shorten the result when necessary.
Note that we don't need an additional case for empty strings, which is a consequence from Haskell's lazyness: If takeWhile sees that the list argument is empty, it doesn't bother to evaluate the condition argument, so head xs doesn't throw an error.

Here's a definition:
import Data.List (group)
short = take 9 . head . group
Interestingly enough, since our returned string is a prefix of the original string, and is constrained to be at most 9 characters long, it doesn't matter whether we trim down to that limit first or last. So we could also use this definition:
short = head . group . take 9
Both of these are written in the "pointfree" style which doesn't reference a lack of punctuation, but a lack of unnecessary variables. We could have also written the definition as
short s = take 9 (head (group s))
Or, using $ to get rid of parentheses:
short s = take 9 $ head $ group s
The only other step is to extract only the first block of matching characters, which is what head . group does (equivalent to your chomp function).
From the docs:
group :: Eq a => [a] -> [[a]]
The group function takes a list and returns a list of lists such that the concatenation of the result is equal to the argument. Moreover, each sublist in the result contains only equal elements. For example,
group "Mississippi" = ["M","i","ss","i","ss","i","pp","i"]
It is a special case of groupBy, which allows the programmer to supply their own equality test.

Related

Shortening a string in Haskell with a condition

Chomp will take the longest amount of repeated characters from a string and one will limit this to 9, e.g. if given the string "aaaaabbbcc" , the answer would be "aaaaa"
I need to define a function, runs, which will do a similiar thing but it will put the string into separate lists, e.g. if the given string is "aaaaabbbccc" , the answer would be ["aaaaa","bbb","cc"], and I need to use the munch function to do this.
The condition of 9 characters applies too, so if the given string is "aaaaaaaaaa" , the answer would be ["aaaaaaaaa","a"]
I've not actually got any implementation apart from something that I found which does pretty much does the same thing without the limit of 9 characters:
runs :: String -> String
runs x = group x
I thought of 2 ways of doing this, but I have no clue on the actual implementation, with one being to run the munch function for however many unique characters there are, i.e if there is an x amount of a , b , c in the given string, it would run 3 times, and then put those lists together into one list.
Another way that I thought of is to use guards. If the number of any single character in the given string is 9 or less, then just use the group function, otherwise, shorten it down using munch, or something like that.
Is anyone able to tell me if the two ideas I mentioned would work at all or suggest an alternative and how to get started? I'm a bit lost.
here is another approach
define a split function to break list at fixed size chunks
splitn :: Int -> [a] -> [[a]]
splitn _ [] = []
splitn n x = take n x : (splitn n $ drop n x)
now you can write your function as
runs = concatMap (splitn 9) . group
A quick google gives you exactly what you're looking for.
https://codereview.stackexchange.com/questions/158183/string-splitting-function-in-haskell
If it works consider upvoting their answer as I only copied a link
The basic strategy here is to take each unique list element to identify successive list elements that are identical. This let you have list elements in any mixed order. There are three functions but no imports.
The first function is rd which creates the list of unique elements.
The second function, t9 is because there might be over 18 of the same elements. t9 will create 9 character long list segments of identical elements with the remainder as the last list (string).
The final, unnamed function uses rd to compile lists of all elements matching each unique elements. It uses t9 to create segments of 9 elements.
l = "bbbbbbbbbaaaaaaaaaaaadddadaaaaaaacccccccccc"
rd [] = []; rd (x:xs) | elem x xs = rd xs | otherwise = x:rd xs
t9 [] = []; t9 xs = [take 9 xs] ++ t9 (drop 9 xs)
[ t | f <- rd l, s <- [[ g | g <- l, f == g ]], t <- t9 s ]
["bbbbbbbbb","dddd","aaaaaaaaa","aaaaaaaaa","aa","ccccccccc","c"]

Proper prefix function in Haskell

I want to create a Haskell function that prints the prefixes of a list:
The function should do the following:
> prefixes "123"
["","1","12"]
> prefixes "1"
[""]
I have written the following code:
prefixes :: [a] -> [[a]]
prefixes [] = []:[]
prefixes f = f : prefixes(init(f))
The function prints the entered string or character as a prefix and prints it in opposite direction. I want to remove it so when I enter "123" it should print as above and display in correct direction.
We can use:
reverse (drop 1 f)
command but I don't know how to implement it in my function.
Can you help me solve this so that it does prints it correctly.
Your base case is incorrect, the empty list has no proper prefixes. So clearly in the base case you must return the empty list for the function to be correct.
Now consider the recursive case. For one, it should always start with the empty list (because the prefixes of (x:xs) are always [[],...]). How can we construct the rest of the list (the non-empty prefixes of (x:xs)?
We want to use recursion, so how do we build the set of non-empty proper prefixes of (x:xs) from the set of proper prefixes of xs? Look at your example "123", the prefixes of "23" are ["", "2"], the non-empty prefixes we want to construct are ["1","12"], so we just add '1' to the head of each prefix of the tail.
So in the recursive case: empty list is a proper prefix, and also the head of the list added to any proper prefix of the tail.
Here is a piece of code that does what you want:
prefixes [] = []
prefixes (x:xs) = [] : map (x:) (prefixes xs)
It looks like you want to know how to define a helper function which would call your original definition.
prefixes xs = reverse (drop 1 (prefixes' xs)) where
prefixes' [] = []:[]
prefixes' f = f : prefixes' (init(f))
Your original definition, while seemingly working, is rather suboptimal though. The other answer shows how to do it more intuotively and without needing a helper function (edit: but the performance may or may not be any good). There are other small things that could be improved in this function:
[]:[] can be written simply as [[]]
drop 1 is tail
parentheses can often be replaced by function composition and $ for better readability.
Here is a solution in point-free style:
prefixes = foldr (\el acc -> [] : map (el:) acc) []

Separating input string and call the required function using case statement

How can I separate the input string into two parts, first of which is a function and the second is the parameter. I want to call the function using the case statement in Haskell.
For example: I have a function sum which calculates the sum of the elements in a list and if a user writes sum 9 it must calculate the sum of the first 9 elements of the list.
First import Data.List, which has all the list manipulation functions.
Then to split at the first space, use span. Then drop the first element of the second half of the list, since that will be the space. The code is then:
import Data.List
f :: String -> (String, String)
f s = (func, tail args)
where (func, args) = span (/=' ') s
EDIT: Oh yeah, for the second part of your question. You're not adding functions to your list of callable functions at runtime right? So just make another function and pattern match on the first argument string, and call the appropriate function. This only works if your always returning an int though. I'm not sure how to make this work on generic return types Example:
eval :: (String, String) -> Int
eval ("sum", args) = sum (take (read . head $ args') (read . concat . tail $ words))
where args' = words args
Use words to split the string at the spaces.
You can then use a case expression and match on the function name and parameters.
If you only want to print the result you can work directly in the IO monad,
which allows you to work with functions of different return types:
evaluationLoop :: IO ()
evaluationLoop = do
input <- getLine
case words input of
"add" : xs -> (print $ sum $ map read xs) >> evaluationLoop
"concat" : xs -> (putStrLn $ concat xs) >> evaluationLoop
"exit" : [] -> return ()
You can then use it like this:
ghci> evaluationLoop
add 1 2 3 4 5
15
add -4 14
10
concat a hello
ahello
concat hi
hi
exit
ghci>

Haskell map (?) operation with different first and last functions

I am writing a Haskell function that operates on a list of ByteString values. I need to do a different operation on the first and last items (which may be the same if the list has only one item).
Specifically, I want to write out the following:
"item-1\
\item-2\
\item-3\
...
\item-n"
where item-1 starts with a double quote and ends with a backslash and item-n starts with a backslash and ends with a double quote. All items between item-1 and item-n start and end with backslashes. I am emitting a base64 encoded value as a Haskell String for some code generation. I have already broken the original (long) base64-encoded ByteString into chunks that are 64 characters long each.
I just realized that my question is a dumb one.
I can just use intercalate to inject the "\\\n\\" between the items and then prepend and append a double quote:
import qualified Data.ByteString.Lazy.Char8 as L
(L.pack "\"") `L.append` (L.intercalate "\\\n\\" items) `L.append` (L.pack "\"")
Sample output:
"H4sIAAAAAA\
\AAA2NgAAMm\
\CMXA7JRYxI\
\Am5JafD2Uy\
\AgDvdHs6Lg\
\AAAA==\
\"
You can also consider splitting your list using:
"head" to get the first element of the list
"tail" to get all but the first element of the list
"init" to get all but the last element of the list
"last" to get the last element of the list
So [head a] ++ init (tail a) ++ [last a] == a.
That way, you can change the first and last elements of the list individually and map a function over the "init" part.
I've been in this situation several times and I've never found a good idiomatic solution. Sometimes intercalate isn't enough. Here's one simple solution.
-- | Annotate elements of a list with Bools, the first of which is True if
-- the element is the head of the list, the second of which is True if the
-- element is the last of the list. Both are True for singleton.
markbounds :: [a] -> [(a, Bool, Bool)]
markbounds [] = []
markbounds [x] = [(x, True, True)]
markbounds (x:xs) = (x, True, False) : tailbound xs
where
tailbound [y] = [(y, False, True)]
tailbound (y:ys) = (y, False, False): tailbound ys
For example:
λ> markbounds [1,2,3]
[(1,True,False),(2,False,False),(3,False,True)]
λ> forM_ (markbounds [1,2,3]) $ \(x, isFirst, isLast) -> when isLast $ print x
3
I have build (my first!) library that has a reasonably-generic solution to the "different first and last functions" question. It's on GitHub (https://github.com/davjam/MapWith) and Hackage (http://hackage.haskell.org/package/MapWith).
Initially inspired by James's markbounds function, but can:
work on more general structures than just lists (all Traversable types)
add parameters directly to a function (not just create tuples)
add different types of parameters (first / last / next element / previous element / index from start or end, etc)
allows creation of additional types of parameter.
add any number of parameters
For example:
> andFirstLast [1,2,3]
[(1,True,False),(2,False,False),(3,False,True)]
> mapWithM_ ((\x isL -> when isL $ print x) & isLast) [1,2,3]
3
> mapWith ((,,,) & isLast & prevElt <-^ eltIx) [1,7,4]
[(1,False,Nothing,2),(7,False,Just 1,1),(4,True,Just 7,0)]
More examples at https://github.com/davjam/MapWith/blob/master/doc/examples.hs.
Any feedback would be gratefully received. Thanks!

Haskell: Minimum sum of list

So, I'm new here, and I would like to ask 2 questions about some code:
Duplicate each element in list by n times. For example, duplicate [1,2,3] should give [1,2,2,3,3,3]
duplicate1 xs = x*x ++ duplicate1 xs
What is wrong in here?
Take positive numbers from list and find the minimum positive subtraction. For example, [-2,-1,0,1,3] should give 1 because (1-0) is the lowest difference above 0.
For your first part, there are a few issues: you forgot the pattern in the first argument, you are trying to square the first element rather than replicate it, and there is no second case to end your recursion (it will crash). To help, here is a type signature:
replicate :: Int -> a -> [a]
For your second part, if it has been covered in your course, you could try a list comprehension to get all differences of the numbers, and then you can apply the minimum function. If you don't know list comprehensions, you can do something similar with concatMap.
Don't forget that you can check functions on http://www.haskell.org/hoogle/ (Hoogle) or similar search engines.
Tell me if you need a more thorough answer.
To your first question:
Use pattern matching. You can write something like duplicate (x:xs). This will deconstruct the first cell of the parameter list. If the list is empty, the next pattern is tried:
duplicate (x:xs) = ... -- list is not empty
duplicate [] = ... -- list is empty
the function replicate n x creates a list, that contains n items x. For instance replicate 3 'a' yields `['a','a','a'].
Use recursion. To understand, how recursion works, it is important to understand the concept of recursion first ;)
1)
dupe :: [Int] -> [Int]
dupe l = concat [replicate i i | i<-l]
Theres a few problems with yours, one being that you are squaring each term, not creating a new list. In addition, your pattern matching is off and you would create am infinite recursion. Note how you recurse on the exact same list as was input. I think you mean something along the lines of duplicate1 (x:xs) = (replicate x x) ++ duplicate1 xs and that would be fine, so long as you write a proper base case as well.
2)
This is pretty straight forward from your problem description, but probably not too efficient. First filters out negatives, thewn checks out all subtractions with non-negative results. Answer is the minumum of these
p2 l = let l2 = filter (\x -> x >= 0) l
in minimum [i-j | i<-l2, j<-l2, i >= j]
Problem here is that it will allow a number to be checkeed against itself, whichwiull lend to answers of always zero. Any ideas? I'd like to leave it to you, commenter has a point abou t spoon-feeding.
1) You can use the fact that list is a monad:
dup = (=<<) (\x -> replicate x x)
Or in do-notation:
dup xs = do x <- xs; replicate x x; return x
2) For getting only the positive numbers from a list, you can use filter:
filter (>= 0) [1,-1,0,-5,3]
-- [1,0,3]
To get all possible "pairings" you can use either monads or applicative functors:
import Control.Applicative
(,) <$> [1,2,3] <*> [1,2,3]
[(1,1),(1,2),(1,3),(2,1),(2,2),(2,3),(3,1),(3,2),(3,3)]
Of course instead of creating pairs you can generate directly differences when replacing (,) by (-). Now you need to filter again, discarding all zero or negative differences. Then you only need to find the minimum of the list, but I think you can guess the name of that function.
Here, this should do the trick:
dup [] = []
dup (x:xs) = (replicate x x) ++ (dup xs)
We define dup recursively: for empty list it is just an empty list, for a non empty list, it is a list in which the first x elements are equal to x (the head of the initial list), and the rest is the list generated by recursively applying the dup function. It is easy to prove the correctness of this solution by induction (do it as an exercise).
Now, lets analyze your initial solution:
duplicate1 xs = x*x ++ duplicate1 xs
The first mistake: you did not define the list pattern properly. According to your definition, the function has just one argument - xs. To achieve the desired effect, you should use the correct pattern for matching the list's head and tail (x:xs, see my previous example). Read up on pattern matching.
But that's not all. Second mistake: x*x is actually x squared, not a list of two values. Which brings us to the third mistake: ++ expects both of its operands to be lists of values of the same type. While in your code, you're trying to apply ++ to two values of types Int and [Int].
As for the second task, the solution has already been given.
HTH

Resources