Cut first x characters from a String in Haskell - string

I'm trying to create a function that concatenates parts of strings in a list to another. I already know how to select the strings I want but now I need the first part of them (and it's not always the same value).
So I want to cut the first part of a string
-- here is a function that should take a string and the numbers
-- of characters we want to take from the start
cutString :: Int -> String -> String
cutString x str = cut x str -- here's a way to take the first x characters
And the way to use it:
print (cutString 3 "Hello World")
Output --> "Hel"
Is there any simple ways to do that?
Thanks for any help or advices.

See take:
take :: Int -> [a] -> [a]
take n, applied to a list xs, returns the prefix of xs of length n, or xs itself if n > length xs
Using it in Prelude shows:
Prelude> take 3 "Hello"
"Hel"

You can implement take yourself with explicit recursion:
-- note the signature here is less general than it need be:
-- cutString :: Int -> [a] -> [a]
cutString :: Int -> String -> String
cutString 0 _ = []
cutString n (x:xs)
| n > 0 = x : cutString (n-1) xs
| otherwise = []
cutString _ _ = []
The first alternation is your usual base case -- taking zero elements of anything is the empty string: [].
The second alternation is your recursive case. If n is zero, execution hits the first alternation, so we only have to worry about two cases here: either n is greater than zero in which case we give back one character and recurse with n-1, or n is less than zero in which case we catch the edge case and give back something sensible. Taking less than zero elements from a string isn't a sensible thing to do, so you could choose your response here -- error might be appropriate.
The third alternation is the fallback and is another base case. If n is still not zero, but we've run out of items in the string, stop recursing and give back []. Without this case, the code crashes on cutString 100 "Hello" (anything where n > length str)

Related

How can I go through a list of numbers and compare it with an another list I am going through?

I want to input two strings, "Hello" and "Hi" for example, and I want to go through every element in the two strings simultaneously and compare every character one by one. The two strings length in the actual program should be 5, if a char is equal to the other, return true, otherwise return false.
The program I have in mind should see 'H' in "Hello" and 'H' from "Hi" and return true, then I want it to check the 'e' in "Hello" and the 'i' in "Hi" and return false. I want it to keep on doing that till there is nothing to compare. I think I might need to use recursion but I am not sure how to implement it in this program really.
I tried using x:xs with the maximum range of 5 so [0..5], but it didn't work at all.
My code (not working):
uncurryingString :: String -> Int -> Char
uncurryingString a b = a !! b
match :: String -> String -> [Int] -> Bool
match a b (x:xs)
| uncurryingString a [x+1 | x <- xs] == uncurryingString b [x+1 | x <- xs] = True
| otherwise = False
You're thinking about this way too complicated.
First, as a rule of thumb, you should never use !! (whether directly or via some helper – uncurryingString is in fact exactly the same as !! itself). If direct indexing is required, a list is not the right data structure. But very often direct indexing is not required, it's just what's customarily used in some other programming languages that don't have pattern matching to do it more elegantly.
In your application, you're deconstructing both strings in parallel. Well, you should express that with a pattern match:
match (a:as) (b:bs) (x:xs) = ...
And now you can simply compare a and b directly, no need for messing about with any list comprehensions or indexing operators. In the example input "Hello" and "Hi", both a and b will be 'H' here.
But you probably don't want to return True right there, because there's still the rest of the string to be matched. That's where recursion comes in.
Finally, you need to clauses in case not all of the input lists are nonempty. Try to figure that out yourself.
What you probably don't need at all is the extra [Int] argument (x:xs). It could make sense to have a depth-limiting argument, but that could be simply an Int. You would then do something like
match :: Eq a => [a] -> [a] -> Int -> Bool
match _ _ 0 = True -- lists are equal up to the specified max depth
match (a:as) (b:bs) n = ...
...
Using a list comprehension is often a good way to compute things in Haskell, but not in this particular case.
I could try this code:
[a==b | a <- "Hello", b <- "Hi"]
What does this do? You might think that this returns True, because the 'H' letters match - or you might thing that this returns False, because the other letters don't match. In fact, it does both - in effect, it is running multiple nested loops.
[True,False,False,False,False,False,False,False,False,False]
So, the takeaway is to use list comprehensions when you want nested loops, or just working through one dataset. Here we just want a single loop that works through the two words in parallel. Hence it must be recursion.

Removing specific elements from lists in Haskell

I'm having a hard time getting Haskell and functional programming together in my head. What I am trying to do is manipulate a string so that I am printing/returning specific characters each time based on a number given. For example:
printing "testing" 2 = "etn"
printing "testing" 3 = "sn"
I've read a lot online, and from what I understand I can achieve this with filtering and cycling, but I cannot get/understand the syntax of this language to get a working program.
I'll try to describe my thought process so you can follow. This function fits the pattern of creating an output list (here a string) from an input seed (here a string) by repeated function application (here dropping some elements). Thus I choose an implementation with Data.List.unfoldr.
unfoldr :: (b -> Maybe (a, b)) -> b -> [a]
Okay so, I need to turn the seed b into (Maybe) an output a and the rest of the string. I'll call this subfunction f and pass it into unfoldr.
printing s n = unfoldr f s
where f b = case drop n b of
[] -> Nothing
(x:xs) -> Just (x,xs)
It turns out that attempting to take the head off the front of the list and returning a Maybe is also a common pattern. It's Data.List.uncons, so
printing s n = unfoldr (uncons . drop n) s
Very smooth! So I test it out, and the output is wrong! Your specified output actually eg. for n=2 selects every 2nd character, ie. drops (n-1) characters.
printing s n = unfoldr (uncons . drop (n-1)) s
I test it again and it matches the desired output. Phew!
To demonstrate the Haskell language some alternative solutions to the accepted answer.
Using list comprehension:
printing :: Int -> String -> String
printing j ls = [s | (i, s) <- zip [1 .. ] ls, mod i j == 0]
Using recursion:
printing' :: Int -> String -> String
printing' n ls
| null ls' = []
| otherwise = x : printing' n xs
where
ls' = drop (n - 1) ls
(x : xs) = ls'
In both cases I flipped the arguments so it is easier to do partial application: printing 5 for example is a new function and will give each 5th character when applied to a string.
Note with a minor modification they will work for any list
takeEvery :: Int -> [a] -> [a]

Haskell Efficient Program

I have this code:
trimorficos :: [Integer]
trimorficos = filter (trim) [0..]
trim :: Integer -> Bool
trim x = (show x) `isSuffixOf` (show (x^3))
where a = show x
b = show (x^3)
densityTrimorficos :: Integer -> Double
densityTrimorficos n = fromInteger (n - (genericLength (filter (<=10) trimorficos))) / fromInteger n
Why the last function densityTrimorficos doesn't work?
trimorficos is an infinite list.
filter (<=10) trimorficos will never produce the end-of-list [] at the very end. To do so, it should verify that, from a certain point onward, trimorficos contains only numbers >10, but that would require infinite time.
Basically, filter will returns something like a:b:c:nonTerminating instead of a:b:c:[] = [a,b,c].
Consequently, genericLength fails to terminate, since it tries to evaluate nonTerminating into either d:... or [] but that requires infinite time.
As pointed out above in the comments, you probably want takeWhile (<=10) trimorficos instead, which will produce [] as soon as the first >10 number is encountered. Note that this will not check the rest of the list, unlike filter.

Haskell converting string to binary number

I need to convert a string of chars to a list of binary numbers in Haskell. I've written two functions to do this, but I'm not sure how to combine them into one. So far I have
dec[]=[]
dec(x:xs) = ord(x): dec xs
to convert every char in the list into a decimal number. The next function
bin 0 = [0]
bin n| n `mod` 2 == 1 = bin (n `div` 2) ++ [1]
| n `mod` 2 == 0 = bin (n `div` 2) ++ [0]
converts a decimal number to its binary equivalent. I'm not sure how to apply the second function to every element in the list, in order to convert every char to its equivalent in binary. I tried to use the where clause:
where n = dec(x:xs) = ord(x): dec xs
but this is not valid as there are two equals signs on the same line. How can I achieve the correct functionality?
You can be pretty certain that an Int will be stored in binary. It only appears to be in decimal because it is converted to decimal when you print it. So, the name dec is a misnomer, that function is converting a String into a sequence of numbers that represent the Unicode value of each character. You can avoid explicit recursion by using map:
toUnicode :: String -> [Int]
toUnicode = map ord
Note that this function uses so-called point-free style. The expected argument is missing, but will be passed to map when supplied by the caller.
The Bin function will not compile because it starts with an upper case character, making it a data constructor. You should name the function starting with a lower case character. According to your example output, you want leading zeros in your binary representations, so you can't stop conversion when the value becomes zero. You need to continue until you have converted the desired number of digits, which appears to be 8. It is also inefficient to keep appending to a list. It is better to prepend, and then reverse the result.
toBinary :: Int -> [Int]
toBinary = go 8 [] where
go 0 acc _ = reverse acc
go n acc x = go (n-1) (bit:acc) x' where
(x', bit) = x `divMod` 2
Here, we use a helper function, go which counts down the number of remaining digits as it builds up the list of 1's and 0's.
So, now we have a function to convert a String into a list of Ints, and a function to convert an Int into a list of 0/1 Ints, and we want to glue them together to make a function that converts a String to a list of 0/1 Ints. If we map our toBinary function over the result of toUnicode, we will get a list of lists, which must be concatenated to form a single list. This is such a common pattern that there's a function for that called, concatMap:
stringToBinary :: String -> [Int]
stringToBinary = concatMap toBinary . toUnicode
Here we use function composition to first apply toUnicode to the String, and then concatMap the toBinary over the result.
What we want is a function of type String -> String (decimal -> binary). What you have now is
dec :: String -> [Int]
bin :: Int -> [Int] -- use *lowercase*
So it seems impossible to compose a function of type String -> String only with these two. Besides, ord is not what you want.
*Main> dec "123"
[49,50,51]
*Main> bin 123
[0,1,1,1,1,0,1,1]
From what you have now, the possible solution would be:
*Main Data.Char> toBinary = map intToDigit . bin . read
*Main Data.Char> toBinary "123"
"01111011"
I guess your intention may be dec :: String -> Int, then bin . dec :: String -> [Int]. You can follow the type signature and retry.

Arithmetic error when trying to add two numbers

I tried to implement a function that takes a limit and a string, parses the string and tests if the parsed number exceeds the limit. The function works well only for strings without 0s in it, like "123". However, it could not parse strings correctly like "100", whose result is 1.
What caused this problem?
Below is the code.
reachBounded :: Int -> String -> Maybe Int
reachBounded limit str = case str of
"" -> Nothing
"0" -> Just 0
_ -> foldr (\digit s -> do
sum <- s
let n = sum * 10 + digitToInt digit
guard (isDigit digit)
guard (n <= limit)
return n)
(Just 0) str
Moreover, is there any way to debug this code like we normally do in imperative languages? I found ghci debugger only able to print the type, not the value.
This is a very imperative way of solving the problem, and if you keep thinking like that you're going to have difficulties moving forward.
Here's how you might want to re-think the problem:
Replace "I have a list of characters, but I want digits, I'll iterate and replace them one by one" with "I have a list of characters but I want digits, I'll just replace them all at once" (I'm going to assume you want to actually parse the string yourself fully manually rather than just using read or some kind of parsing tool)
So far we have:
reachBounded limit str = ... map digitToInt str
Next, you want to turn these digits into a number. Replace "I want to iterate through this list increment a sum" with "I need to know the place value of each digit". We can do this by reversing the digits and multiplying them pairwise with the list [1,10,100,1000...]. We can produce the place value list by mapping (10^) over the list of positive integers, or declaring that each element is 10 times the previous, starting with 1. Let's use the latter:
reachBounded limit str = ... zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
And we want the sum of these place values:
reachBounded limit str = ... where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
Lastly, we must check if it's within the bound given:
reachBounded limit str = val <$ guard (val < limit) where
val = sum $ zipWith (*) (iterate (*10) 1) $ reverse $ map digitToInt str
In this case a <$ b will replace the contents of b with a if b is Just something, and leave it alone if b is Nothing.
In terms of debugging, it is now trivial, as it is not some process we need to interrupt, but a series of values that we manipulate to get the desired result. You cannot run part of your process on each step and get a sensible answer, but here we can look at the result produced by any of these stages and see if we are on track.
There isn't a toMaybe :: (a -> Bool) -> a -> Maybe a function. I'm not sure why, but with one and using read, the solution is merely:
bounded l = toMaybe (<l) . read
Or using the Safe library...
bounded l = toMaybe (<l) <=< readMay
Which will not throw exceptions if you don't input a string that actually represents a number.
Now, let's say you really do want to write your algorithm iteratively, maybe you need to for performance or it's just one of those algorithms that doesn't readily admit a declarative implementation (there aren't many of those, though). It's still going to be cleaner to use values instead of exceptions, but you need to stop and look at it sometimes.. so what do you do?
Let's write our own iterator function:
data Iter a b c = Next a | Final b | Error c
iterateE :: (a -> Iter a b c) -> a -> ([a], Either c b)
iterateE f = go where
go x = case f x of
Next a -> let (list, final) = go a in (x:list, final)
Final b -> ([x], Right b)
Error c -> ([x], Left c)
This more directly encapsulates stopping the fold early and tracking the intermediate results - even though you can also just stop folds early and track the intermediate results - this is a simpler way to think about it for now. This will provide you with a complete list of all intermediate states and either a result or error that your iterator function can choose to terminate with.
Transforming your solution into this format...
reachBounded limit str = iterateE iter (Just 0,str) where
iter (n, []) = Final n
iter (n, (s:str)) = Next (do
sum <- s
let n = sum * 10 + digitToInt digit
guard (isDigit digit)
guard (n <= limit)
return n, str)
... we don't don't announce any error in this code, but this will let us see what's happened at each step, and also doesn't have a direction in the fold, so you can't get it backwards between left and right.

Resources