Haskell Get position from first digit in string - string

What I got is
digitIndex :: String -> Int
digitIndex [] = 1
digitIndex (x:xs) =
if
isDigit x == True
then
-- Count list
else
-- Create list with x(x is not a digit)
What my idea is is to make a list with all the x that he is passing so when he passes a digit he only needs to count the list and that will be the position of the digit(when you count a +1).
Only thing is I don't know how to get the job more done. Can you guys help me out with tips?

You can use findIndex:
import Data.List
digitIndex :: String -> Int
digitIndex = maybe 0 id . findIndex isDigit

Just the normal recursion:
digitIndex :: String -> Int
digitIndex [] = 0
digitIndex (x:xs) = if isDigit x
then 1
else 1 + digitIndex xs
If the first character itself is a digit, then the function returns 1 else it just adds 1 and passes the remaining string (xs) to the function and the recursion goes on.
Also note that the above function doesn't work properly when the String doesn't have a number at all.
And also checking isDigit == True isn't necessary.

Related

How can I add n whitespaces after a string with recursion in Haskell?

For example a number (5) and a string (apple) is given, and the program drops (apple_____).
I want to do this with recursion. I tried this way:
add :: Integer -> [Char] -> [Char]
add 0 (x:xs) = (x:xs)
add i [] = add (i-1) [] ++ " "
add i (x:xs) = format (i-1) xs
Given you want to add 0 spaces, you can return the given string (1); if the string is non-empty, you emit the first element of the string x and recurse on the tail of the string (2); finally if we reached the end of the string, and i is greater than 0, we emit a space, and recurse with i one less than the given i (3):
add :: Integer -> String -> String
add i xs | i <= 0 = xs -- (1)
add i (x:xs) = x : … -- (2)
add i [] = ' ' : … -- (3)
You here still need to fill in the … parts.

convert string of digits to int in Haskell

I am trying to write this function in Haskell called scanString, which takes a string and convert it into int if it's composed of only digits and should return 0 otherwise.
For example, scanString "123" = 123 but scanString "12a" = 0.
Here's my implementation so far:
scanChar :: Char -> Int
scanChar c
| 48 <= fromEnum c && fromEnum c <= 57 = (fromEnum c) - fromEnum '0'
| otherwise = 0
scanString :: String -> Int
scanString str = case str of
[] -> 0
x:xs
| 48 <= fromEnum x && fromEnum x <= 57 ->
((scanChar x) * (10 ^ ((length str) -1 ))) + scanString xs
| otherwise -> 0
This code does not do the right thing as scanString "3a" would give 30.
Is there a way (like in Java or Python) where one can simply terminate a function and return a value? Of course, advice on the implementation on this function would be awesome!
Thanks in advance!
The main problem here I think is that you let scanChar :: Char -> Int return both a zero for the zero character ('0') as well as for other characters. As a result the scanString has to include extra logic and this makes it only more complex.
So we can clean the scanChar by for instance returning a -1 (or we could let it return a Maybe Int and let it return Nothing, regardless how you exactly specify it, the key is to try to encapsulate the checking logic in one function, such that we no longer have to care about it). So for example:
scanChar :: Char -> Int
scanChar c | '0' <= c && c <= '9' = fromEnum c - fromEnum '0'
| otherwise = -1
So now we can encapsulate all the digit parsing logic in scanChar. Now we still need to implement scanString :: String -> Int. This can be done by writing an extra function that works with an accumulator. For example:
scanString :: String -> Int
scanString = go 0
where go a s = ...
So here go acts as a function to emulate some sort of while loop. The a parameter is the accumulator, a parameter we pass through recursive calls and each time we can update it with more data. Initially we set it to zero.
The go function has basically three cases:
the end of the string is reached, we can return the accumulator;
the first character of the string is not a digit, we return 0; and
the first character of the string is a digit, we multiply the accumulator with 10, add the parsed value, and perform recursion on the tail of the string.
We can thus implement those three cases like:
scanString :: String -> Int
scanString = go 0
where go a [] = a
go a (x:xs) | 0 <= sc && sc <= 9 = go (10*a+sc) xs
| otherwise = 0
where sc = scanChar x
So you're limited by the specification of the problem that the outermost question be of type String -> Int, but that doesn't mean that your helper function scanChar can't return Maybe Int.
So let's look at doing that:
scanChar :: Char -> Maybe Int
scanChar c
| 48 <= fromEnum c && fromEnum c <= 57 = Just $ (fromEnum c) - fromEnum '0'
| otherwise = Nothing
Now, using the approach in the other answer:
scanString :: String -> Int
scanString = go 0
where go a [] = a
go a (x:xs) = case (scanChar x) of
Nothing -> 0
Just d -> go (10*a + d) xs
where sc = scanChar x
Why not
scanString :: String -> Int
scanString x = if all (`elem` "0123456789") x
then read x :: Int
else 0
Note: it will not read negative integers.
Or:
import Data.Char (isDigit)
scanString' :: String -> Int
scanString' x = if all isDigit x
then read x :: Int
else 0
Also a simple solution here using readMaybe.
You can make the following into a function with one parameter that is a string. This function will take only digits out of the string and pack them into another string which is then then converted.
[read [d | d <- "12a", elem d "1234567890"] :: Int] !! 0
Yields 12

Function containing head and tail functions throws empty list error

I'm trying the solve the first question in Advent of Code 2017, and come up with the following solution to calculate the needed value:
checkRepetition :: [Int] -> Bool
checkRepetition [] = False
checkRepetition (x:xs)
| x == ( head xs ) = True
| otherwise = False
test :: [Int] -> Int
test [] = 0
test [x] = 0
test xs
| checkRepetition xs == True = ((head xs)*a) + (test (drop a xs))
| otherwise = test (tail xs)
where
a = (go (tail xs)) + 1
go :: [Int] -> Int
go [] = 0
go xs
| checkRepetition xs == True = 1 + ( go (tail xs) )
| otherwise = 0
However, when I give an input that contains repetitive numbers such as [1,3,3], it gives the error
*** Exception: Prelude.head: empty list
However, for 1.5 hours, I couldn't figure out exactly where this error is generated. I mean any function that is used in test function have a definition for [], but still it throws this error, so what is the problem ?
Note that, I have checked out this question, and in the given answer, it is advised not to use head and tail functions, but I have tested those function for various inputs, and they do not throw any error, so what exactly is the problem ?
I would appreciate any help or hint.
As was pointed out in the comments, the issue is here:
checkRepetition (x:xs)
| x == ( head xs ) = True
xs is not guaranteed to be a non-empty list (a one-element list is written as x:[], so that (x:xs) pattern matches that xs = []) and calling head on an empty list is a runtime error.
You can deal with this by changing your pattern to only match on a 2+ element list.
checkRepetition [] = False
checkRepetition [_] = False
checkRepetition (x1:x2:_) = x1 == x2
-- No need for the alternations on this function, by the way.
That said, your algorithm seems needlessly complex. All you have to do is check if the next value is equal, and if so then add the current value to the total. Assuming you can get your String -> [Int] on your own, consider something like:
filteredSum :: [Int] -> Int
filteredSum [] = 0 -- by definition, zero- and one-element lists
filteredSum [_] = 0 -- cannot produce a sum, so special case them here
filteredSum xss#(first:_) = go xss
where
-- handle all recursive cases
go (x1:xs#(x2:_)) | x1 == x2 = x1 + go xs
| otherwise = go xs
-- base case
go [x] | x == first = x -- handles last character wrapping
| otherwise = 0 -- and if it doesn't wrap
-- this should be unreachable
go [] = 0
For what it's worth, I think it's better to work in the Maybe monad and operate over Maybe [Int] -> Maybe Int, but luckily that's easy since Maybe is a functor.
digitToMaybeInt :: Char -> Maybe Int
digitToMaybeInt '0' = Just 0
digitToMaybeInt '1' = Just 1
digitToMaybeInt '2' = Just 2
digitToMaybeInt '3' = Just 3
digitToMaybeInt '4' = Just 4
digitToMaybeInt '5' = Just 5
digitToMaybeInt '6' = Just 6
digitToMaybeInt '7' = Just 7
digitToMaybeInt '8' = Just 8
digitToMaybeInt '9' = Just 9
digitToMaybeInt _ = Nothing
maybeResult :: Maybe Int
maybeResult = fmap filteredSum . traverse digitToMaybeInt $ input
result :: Int
result = case maybeResult of
Just x -> x
Nothing -> 0
-- this is equivalent to `maybe 0 id maybeResult`
Thank you for the link. I went there first to glean the purpose.
I assume the input will be a string. The helper function below constructs a numeric list to be used to sum if predicate is True, that is, the zipped values are equal, that is, each number compared to each successive number (the pair).
The helper function 'nl' invokes the primary function 'invcap' Inverse Captcha with a list of numbers.
The nl function is a list comprehension. The invcap function is a list comprehension. Perhaps the logic in this question is at fault. Overly complicated logic is more likely to introduce errors. Proofs are very much easier when logic is not cumbersome.
The primary function "invcap"
invcap l = sum [ x | (x,y) <- zip l $ (tail l) ++ [head l], x == y]
The helper function that converts a string to a list of digits and invokes invcap with a list of numeric digits.
nl cs = invcap [ read [t] :: Int | t <- cs]
Invocation examples
Prelude> nl "91212129" ......
9 ' ' ' ' ' ' ' ' ' ' ' ' '
Prelude> nl "1122" ......
3

Recursively dropping elements from list in Haskell

Right now I'm working on a problem in Haskell in which I'm trying to check a list for a particular pair of values and return True/False depending on whether they are present in said list. The question goes as follows:
Define a function called after which takes a list of integers and two integers as parameters. after numbers num1 num2 should return true if num1 occurs in the list and num2 occurs after num1. If not it must return false.
My plan is to check the head of the list for num1 and drop it, then recursively go through until I 'hit' it. Then, I'll take the head of the tail and check that against num2 until I hit or reach the end of the list.
I've gotten stuck pretty early, as this is what I have so far:
after :: [Int] -> Int -> Int -> Bool
after x y z
| y /= head x = after (drop 1 x) y z
However when I try to run something such as after [1,4,2,6,5] 4 5 I get a format error. I'm really not sure how to properly word the line such that haskell will understand what I'm telling it to do.
Any help is greatly appreciated! Thanks :)
Edit 1: This is the error in question:
Program error: pattern match failure: after [3,Num_fromInt instNum_v30 4] 3 (Num_fromInt instNum_v30 2)
Try something like this:
after :: [Int] -> Int -> Int -> Bool
after (n:ns) a b | n == a = ns `elem` b
| otherwise = after ns a b
after _ _ _ = False
Basically, the function steps through the list, element by element. If at any point it encounters a (the first number), then it checks to see if b is in the remainder of the list. If it is, it returns True, otherwise it returns False. Also, if it hits the end of the list without ever seeing a, it returns False.
after :: Eq a => [a] -> a -> a -> Bool
after ns a b =
case dropWhile (/= a) ns of
[] -> False
_:xs -> b `elem` xs
http://hackage.haskell.org/package/base-4.8.2.0/docs/src/GHC.List.html#dropWhile
after xs p1 p2 = [p1, p2] `isSubsequenceOf` xs
So how can we define that? Fill in the blanks below!
isSubsequenceOf :: Eq a => [a] -> [a] -> Bool
[] `isSubsequenceOf` _ = ?
(_ : _) `isSubsequenceOf` [] = ?
xss#(x : xs) `isSubsequenceOf` (y:ys)
| x == y = ?
| otherwise = ?
after :: [Int] -> Int -> Int -> Bool
Prelude> let after xs a b = elem b . tail $ dropWhile (/=a) xs
Examples:
Prelude> after [1,2,3,4,3] 88 7
*** Exception: Prelude.tail: empty list
It raises an exception because of tail. It's easy to write tail' such that it won't raise that exception. Otherwise it works pretty well.
Prelude> after [1,2,3,4,3] 2 7
False
Prelude> after [1,2,3,4,3] 2 4
True

Haskell error Main.hs:(39,1)-(44,64): Non-exhaustive patterns in function sumList

Can you help me with this issue? The compiler generate this error:
Haskell error Main.hs:(39,1)-(44,64):
Non-exhaustive patterns in function sumList
My code is
sumList:: [[Char]] -> [Char] -> Float
sumList [] element = 0
sumList (x:xs) element
|x == [] = 0
|xs == [] = 0
|x == "" = 0
|((splitOn "|" x)!!1) == element = 1 + (sumList xs element)
I fixed it ,
need to add one more line to deal with the other situation
which is
|otherwise = (sumList xs element)
I find your goal and code quite blur :
Why the Float type ? Are you not trying to count something?
Are x == [] = 0 and x == "" = 0 really both necessary ? How are they different?
I guessed that you wanted to count some elements, having some kind of tag.
Tell me if I'm wrong.
I ended up with this code (not sure it corresponds to your problem) :
hasTag :: String -> String -> Bool
hasTag tag word = case splitOn "|" word of
_:[] -> False -- No tag
_:tags -> tag `elem` tags
countHavingTag :: String -> [String] -> Int
countHavingTag tag = length . filter (hasTag tag)
Explicit recursion is quite un-idiomatic in Haskell, you usually don't need it.
You probably want to learn more about :
types
recursion (base case and recursion rules)
partial function

Resources