FP101x Lab 2 sumDigits - haskell

I'm stuck on Lab 2 of the Functional Programming course on edX taught by Erik Meijer. I will copy paste the assignment here:
In this lab, you will implement a validation algorithm for credit cards. The algorithm follows these steps:
Double the value of every second digit beginning with the rightmost.
Add the digits of the doubled values and the undoubled digits from the original number.
Calculate the modulus of the sum divided by 10.
If the result equals 0, then the number is valid. Here is an example of the results of each step on the number 4012888888881881.
In order to start with the rightmost digit, we produce a reversed list of digits. Then, we double every second digit.
Result: [1,16,8,2,8,16,8,16,8,16,8,16,2,2,0,8].
We sum all of the digits of the resulting list above. Note that we must again split the elements of the list into their digits (e.g. 16 becomes [1, 6]).
Result: 90.
Finally, we calculate the modulus of 90 over 10.
Result: 0.
Since the final value is 0, we know that the above number is a valid credit card number. If we make a mistake in typing the credit card number and instead provide 4012888888881891, then the result of the last step is 2, proving that the number is invalid.
My code:
toDigits :: Integer -> [Integer]
toDigits n = if 0 <= n && n <= 10 then [n] else toDigits ((n - n `mod` 10) `quot` 10) ++ [n `mod` 10]
toDigitsRev :: Integer -> [Integer]
toDigitsRev n = reverse (toDigits n)
doubleSecond :: [Integer] -> [Integer]
doubleSecond xs | length xs <= 1 = xs
| 1 < length xs && length xs < 4 = [fst (splitAt 2 xs) !! 0 ,(*2) (fst (splitAt 2 xs) !! 1 )] ++ snd (splitAt 2 xs)
| otherwise = doubleSecond (fst (splitAt 2 xs)) ++ doubleSecond (snd (splitAt 2 xs))
sumDigits :: [Integer] -> Integer
sumDigits xs | xs == [] = 0
| otherwise = sum (toDigits (head xs)) + sumDigits (tail xs)
isValid :: Integer -> Bool
isValid n | sumDigits (doubleSecond (toDigitsRev n)) `mod` 10 == 0 = True
| otherwise = False
Next, they give you this code:
numValid :: [Integer] -> Integer
numValid xs = sum . map (\_ -> 1) $ filter isValid xs
creditcards :: [Integer]
creditcards = [ 4716347184862961,
4532899082537349,
4485429517622493,
4320635998241421,
4929778869082405,
5256283618614517,
5507514403575522,
5191806267524120,
5396452857080331,
5567798501168013,
6011798764103720,
6011970953092861,
6011486447384806,
6011337752144550,
6011442159205994,
4916188093226163,
4916699537435624,
4024607115319476,
4556945538735693,
4532818294886666,
5349308918130507,
5156469512589415,
5210896944802939,
5442782486960998,
5385907818416901,
6011920409800508,
6011978316213975,
6011221666280064,
6011285399268094,
6011111757787451,
4024007106747875,
4916148692391990,
4916918116659358,
4024007109091313,
4716815014741522,
5370975221279675,
5586822747605880,
5446122675080587,
5361718970369004,
5543878863367027,
6011996932510178,
6011475323876084,
6011358905586117,
6011672107152563,
6011660634944997,
4532917110736356,
4485548499291791,
4532098581822262,
4018626753711468,
4454290525773941,
5593710059099297,
5275213041261476,
5244162726358685,
5583726743957726,
5108718020905086,
6011887079002610,
6011119104045333,
6011296087222376,
6011183539053619,
6011067418196187,
4532462702719400,
4420029044272063,
4716494048062261,
4916853817750471,
4327554795485824,
5138477489321723,
5452898762612993,
5246310677063212,
5211257116158320,
5230793016257272,
6011265295282522,
6011034443437754,
6011582769987164,
6011821695998586,
6011420220198992,
4716625186530516,
4485290399115271,
4556449305907296,
4532036228186543,
4916950537496300,
5188481717181072,
5535021441100707,
5331217916806887,
5212754109160056,
5580039541241472,
6011450326200252,
6011141461689343,
6011886911067144,
6011835735645726,
6011063209139742,
379517444387209,
377250784667541,
347171902952673,
379852678889749,
345449316207827,
349968440887576,
347727987370269,
370147776002793,
374465794689268,
340860752032008,
349569393937707,
379610201376008,
346590844560212,
376638943222680,
378753384029375,
348159548355291,
345714137642682,
347556554119626,
370919740116903,
375059255910682,
373129538038460,
346734548488728,
370697814213115,
377968192654740,
379127496780069,
375213257576161,
379055805946370,
345835454524671,
377851536227201,
345763240913232
]
You are supposed to run numValid creditcards and get 94, I'm getting 39.
I suspect my mistake is in sumDigits but can't really find it, any help is much appreciated.

Let's try to find those errors. We're going to use QuickCheck to test several properties. Let's start with some properties for toDigits:
toDigits_prop n = n >= 0 ==> length (toDigit n) === length (show n)
It will fail after some tests with something like this:
*Main> quickCheck toDigits_prop
*** Failed! Falsifiable (after 24 tests):
10
1 /= 2
This means that we got only one digit on 10, where we originally expected two. Let's check the result of toDigits on 10:
*Main> toDigits 10
[10]
Aha. There's a logic error on toDigits, the behaviour on the bounds is wrong, 10 isn't a digit. So change that to <= 9 instead <= 10. While we're at it let's simplify that function, since there is quotRem to get both the reminder and quot at the same time:
toDigits :: Integer -> [Integer]
toDigits n = case n `quotRem` 10 of
(0, m) -> [m] -- only one digit was left
(q, m) -> toDigits q ++ [m]
Note that this function is somewhat inefficient, we can make it faster if we reverse the digits at the same time:
toDigitsRev :: Integer -> Integer
toDigitsRev n = case n `quotRem` 10 of
(0, m) -> [m] -- only one digit was left
(q, m) -> m : toDigitsRev q -- add current digit left
Either way, let's check whether the new version of toDigits holds:
*Main> quickCheck toDigits_prop
+++ OK, passed 100 tests.
Allright. Let's check whether this passes all tests:
*Main> numValid creditcards
94
Seems like now everything is fine. So the key is to check properties of your functions. Note that several functions can be written easier, e.g.
doubleSecond :: Num a => [a] -> [a]
doubleSecond xs = zipWith ($) (cycle [id, (2*)]) xs
-- or
doubleSecond (x:y:xs) = x : 2 * y : doubleSecond xs
doubleSecond xs = xs
sumDigits :: [Integer] -> Integer
sumDigits xs = sum (concatMap toDigits xs)

Related

Is it possible to store a removed value in haskell

Hi I am new to haskell and I was just wondering whether it was possible to store a value that has already been removed:
This is my code
input :: Integer -> String
input x = checklength $ intolist x
intolist 0 = []
intolist x = intolist (x `div` 10) ++ [x `mod` 10]
checklength x = if length(x) >= 13 && length(x) <= 16 then doubleall
(init(x)) else "Not valid length of credit card number"
doubleall x = finalcheck $ final $ double (reverse (x))
double x = case x of
[] -> []
[x] -> if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]
x:y:xs -> (if (x*2 < 10) then [x*2] else [x*2 `div` 10 + x*2 `mod` 10]) ++
y:double xs
final x = (sum x) * 9
finalcheck x = if (x `mod` 10 == ...... ) then "True" else "False"
My code basically takes an input as an integer such as 987564736264535. then makes this integer into a list of number such as [9,8,7..5]. Then it checks the length has to between 13 to 16 digits. If not you get an error statement. If the digits are between the required amount it will go into the doubeall function and remove the last number using (init). the number removed is 5 in which it will double the numbers and reverse the list order. It will then sum the numbers together and multiple by 9. The final step that I have done part of is taking the last digit of the number that has already been summed together and multiplied by 9. So lets give and example lets say I get 456 then I use mod 10 to take the last number which is 6. **Now here is where I am having a problem in which I want to check whether this 6 is equal to the same number that was removed originally in the checklength function when I used init. So in the checklength function I removed the number 5 **
Thanks
Once you remove data, you can't access it again. You need a function that preserves the final checkdigit that you're stripping off.
Since order is (mostly) irrelevant, consider:
validate :: Integer -> Bool
validate x = let digits = toDigits x
in if checkLength digits
then doesMatch . splitCheckdigit $ digits
else False
where
toDigits 0 = [0]
toDigits x = go x
where
go 0 = []
go x = let (d, m) = x `divMod` 10
in m : toDigits d
-- reverses order
checkLength x = let l = length x
in 13 <= l && l <= 16
splitCheckdigit (checkdigit:rest) = (checkdigit, rest)
-- remember we reversed in toDigits, so the *first* digit is the checkdigit!
doesMatch (checkdigit, rest) = let total = (*9) . sum . reduce $ rest
shouldBe = total `mod` 10
in checkdigit == shouldBe
where
reduce (x:y:xs) = (sum . toDigits $ x) : y : reduce xs
reduce [x] = [sum . toDigits $ x]
reduce [] = []
-- note how #toDigits# is reused here rather than redefined.
If you prefer Arrows, validate can be written as:
toDigits >>> ((doesMatch <<< splitCheckdigit) &&& checkLength) >>> uncurry (&&)

Haskell: last digit of a very large number

I'm trying to work out the last digit of a very large number. The challenge is that I'm getting the error
*** Exception: Prelude.!!: negative index
which I don't think should be possible. This happens when I try:
lastDigit [27,15,14]
Here is my code, which is based on https://brilliant.org/wiki/finding-the-last-digit-of-a-power/:
In this case, n becomes 7 and modList 7 gives the recurring sequence [1,7,9,3,1,7,9,3...], which is the first argument of (!!) in the relevant guard. The second argument of (!!) gives 1 because (y:ys) is (15,14) and rem (powers (15 ^ 14)) 4 is 1. Please help.
lastDigit :: [Integer] -> Integer
lastDigit [] = 1
lastDigit [x] = x `mod` 10
lastDigit [x,y] = x ^ y `mod` 10
lastDigit (x:y:ys)
| y == 0 && head ys /= 0 = 1
| n == 0 = 0
| n == 9 || n == 4 = (!!) (modList n) (rem (fromIntegral $ powers (y:ys)) 2)
| n == 2 || n == 3 || n == 7 || n == 8 = (!!) (modList n) (rem (fromIntegral $ powers (y:ys)) 4)
| otherwise = n
where n = mod x 10
powers xs = foldr1 (^) xs
modList n = drop 3 . take 30 $ cycle [mod x 10| x <- map (n^) $ take 4 [1..]]
You should be very specific about the types, otherwise they might get implicit converted during calculations. If you add Int type to your algorithm, ghc will not complain and run into an negative index exception
(fromIntegral $ powers (y:ys)) 2 :: Int)
but if you provide
(fromIntegral $ powers (y:ys)) 2 :: Integer)
it will result in
• Couldn't match expected type ‘Int’ with actual type ‘Integer’
• In the second argument of ‘(!!)’, namely
‘(rem (fromIntegral $ powers (y : ys)) 2 :: Integer)’
As you can see you have an implicit Int conversion there. Try to split up your function into smaller ones and provide a type signature, then you should be able to successfully align the types and calculate with Integers instead of Int.

Write the recursive function adjuster

Write the recursive function adjuster. Given a list of type
x, an int and an element of type x, either remove from the front of the
list until it is the same length as int, or append to the end of the list
until it is the same length as the value specified by the int.
expected:
adjuster [1..10] (-2) 2 -> *** Exception: Invalid Size
adjuster [1..10] 0 2 -> []
adjuster "apple" 10 ’b’ -> "applebbbbb"
adjuster "apple" 5 ’b’ -> "apple"
adjuster "apple" 2 ’b’ -> "le"
adjuster [] 3 (7,4) -> [(7,4),(7,4),(7,4)]
What i did:
adjuster (x:xs) count b
| count < 0 = error "Invalid Size"
| count == 0 = []
| count < length xs = adjuster xs (count-1) b
| otherwise = (adjuster xs (count-1) b):b
the error that I'm getting:
* Occurs check: cannot construct the infinite type: t ~ [t]
Expected type: [t]
Actual type: [[t]]
* In the expression: (adjuster xs (count - 1) b) : b
In an equation for `adjuster':
adjuster (x : xs) count b
| count < 0 = error "Invalid Size"
| count == 0 = []
| count < length xs = adjuster xs (count - 1) b
| otherwise = (adjuster xs (count - 1) b) : b
* Relevant bindings include
b :: [[t]] (bound at code01.hs:21:23)
adjuster :: [a] -> Int -> [[t]] -> [t] (bound at code01.hs:21:1)
I'm new in haskell.I'll really appreciate some help.
You are trying to construct a list within lists within lists and so on and so forth …
Why is this?
(:) :: a -> [a] -> [a]
The colon operator takes an element and a list of such elements as an argument and constructs a list from that (by prepending that element).
In your case if (adjuster ...) had type [a] then b must be of type [[a]], by line 4 which is the same as the end result, but line 3 says the type is [a] - which is different. This is what GHC tries to tell you.
How to fix it?
First of all, it is always a good advice to add a type signature to every top level function:
adjuster :: [a] -> Int -> a -> [a]
which should clean up your error-message and keep you honest, when implementing your function.
So how to fix this: - you could use b:adjuster xs (count-1) b but this would yield a result in the wrong order - so
choose a different operator: (++) and wrap the b inside a list.
| otherwise = (adjuster xs (count-1) b)++[b]
Now a few more hints:
turn on -Wall when you compile your file - this will show you that you missed the case of adjuster [] ...
using length is a relatively expensive operation - as it needs to traverse the full list to be calculated.
As an exercise - try to modify your function to not use length but only work with the base cases [] for list and 0 for count (here the function replicate might be helpful).
Here is another approach, without error handling
adjuster xs n v = tnr n $ (++) (replicate n v) $ tnr n xs
where tnr n r = take n $ reverse r
if you play with the signature, perhaps cleaner this way
adjuster n v = tnr . (++) (replicate n v) . tnr
where tnr = take n . reverse

Haskell reverse Integer with recursion

I want to reverse an Integer in Haskell with recursion. I have a small issue.
Here is the code :
reverseInt :: Integer -> Integer
reverseInt n
| n>0 = (mod n 10)*10 + reverseInt(div n 10)
| otherwise = 0
Example 345
I use as input 345 and I want to output 543
In my program it will do....
reverseInt 345
345>0
mod 345 10 -> 5
reverseInt 34
34
34>0
mod 34 10 -> 4
reverseInt 3
3>0
mod 3 10 -> 3
reverseInt 0
0=0 (ends)
And at the end it returns the sum of them... 5+4+3 = 12.
So I want each time before it sums them, to multiple the sum * 10. So it will go...
5
5*10 + 4
54*10 + 3
543
Here's a relatively simple one:
reverseInt :: Int -> Int
reverseInt 0 = 0
reverseInt n = firstDigit + 10 * (reverseInt $ n - firstDigit * 10^place)
where
n' = fromIntegral n
place = (floor . logBase 10) n'
firstDigit = n `div` 10^place
Basically,
You take the logBase 10 of your input integer, to give you in what place it is (10s, 100s, 1000s...)
Because the previous calculation gives you a floating point number, of which we do not need the decimals, we use the floor function to truncate everything after the decimal.
We determine the first digit of the number by doing n 'div' 10^place. For example, if we had 543, we'd find place to be 2, so firstDigit = 543/100 = 5 (integer division)
We use this value, and add it to 10 * the reverse of the 'rest' of the integer, in this case, 43.
Edit: Perhaps an even more concise and understandable version might be:
reverseInt :: Int -> Int
reverseInt 0 = 0
reverseInt n = mod n 10 * 10^place + reverseInt (div n 10)
where
n' = fromIntegral n
place = (floor . logBase 10) n'
This time, instead of recursing through the first digit, we're recursing through the last one and using place to give it the right number of zeroes.
reverseInt :: Integer -> Integer
reverseInt n = snd $ rev n
where
rev x
| x>0 = let (a,b) = rev(div x 10)
in ((a*10), (mod x 10)*a + b)
| otherwise = (1,0)
Explanation left to reader :)
I don't know convenient way to found how many times you should multiply (mod n 10) on 10 in your 3rd line. I like solution with unfoldr more:
import Data.List
listify = unfoldr (\ x -> case x of
_ | x <= 0 -> Nothing
_ -> Just(mod x 10, div x 10) )
reverse_n n = foldl (\ acc x -> acc*10+x) 0 (listify n)
In listify function we generate list of numbers from integer in reverse order and after that we build result simple folding a list.
Or just convert it to a string, reverse it and convert it back to an integer:
reverseInt :: Integer -> Integer
reverseInt = read . reverse . show
More (not necessarily recursion based) answers for great good!
reverseInt 0 = 0
reverseInt x = foldl (\x y -> 10*x + y) 0 $ numToList x
where
numToList x = if x == 0 then [] else (x `rem` 10) : numToList (x `div` 10)
This is basically the concatenation of two functions : numToList (convert a given integer to a list 123 -> [1,2,3]) and listToNum (do the opposite).
The numToList function works by repeatedly getting the lowest unit of the number (using rem, Haskell's remainder function), and then chops it off (using div, Haskell's integer division function). Once the number is 0, the empty list is returned and the result concatenates into the final list. Keep in mind that this list is in reverse order!
The listToNum function (not seen) is quite a sexy piece of code:
foldl (\x y -> 10*x + y) 0 xs
This starts from the left and moves to the right, multiplying the current value at each step by 10 and then adding the next number to it.
I know the answer has already been given, but it's always nice to see alternative solutions :)
The first function is recursive to convert the integer to a list. It was originally reversing but the re-conversion function reversed easier so I took it out of the first. The functions can be run separately. The first outputs a tuple pair. The second takes a tuple pair. The second is not recursive nor did it need to be.
di 0 ls = (ls,sum ls); di n ls = di nn $ d:ls where (nn,d) = divMod n 10
di 3456789 []
([3,4,5,6,7,8,9],42)
rec (ls,n) = (sum [y*(10^x)|(x,y) <- zip [0..] ls ],n)
Run both as
rec $ di 3456789 []
(9876543,42)

Convert Negative-base binary to Decimal in Haskell: "Instances of .. required"

I have to write two functions converting decimal numers into a (-2)adian number system (similar to binary only with -2) and vice versa.
I already have managed to get the decimal -> (-2)adian running.
But with (-2)adian -> decimal I have a problem and just don't know where to begin.
Hope you can Help me
type NegaBinary = String
-- Function (-2)adisch --> decimal
negbin_dezi :: NegaBinary -> Integer -> Integer
negbin_dezi (xs:x) n
| (x == 0) = if ([xs] == "") then 0 else (negbin_dezi [xs] (n+1))
| (x == 1) = if ([xs] == "") then (-2)**n else (-2)**n + (negbin_dezi [xs] (n+1))
It always throws:
"Instances of (Num [Char], Floating Integer) required for definition of negbin_dezi.
Anyone an idea why it wont work?
Please please please :)
You have your list pattern-matching syntax backwards. In _ : _ the first argument is the head of the list (one element), and the second is the tail of the list (another list). e.g. x:xs matched with "abc" gives x = 'a' xs = "bc". So xs:x should be x:xs. The reason for GHC asking for an instance of Num [Char], is the comparison x == 0 (and x == 1). In this, it is trying to match the type of x (String == [Char]) with the type of 0 (Num a => a), and to do this, it requires a Num instance for String.
The fix is: negbin_dezi (x:xs) n
The problem asking for an Floating Integer instance is because (**) has type Floating a => a -> a -> a, where as you want (^) which has type (Num a, Integral b) => a -> b -> a (i.e. it is restricted to integer powers.)
Once you've done this, you'll find that your algorithm doesn't work for a few reasons:
The number 0 is different to the character '0', you should be comparing x with the characters '0' and '1' rather than the numbers 0 and 1.
xs is already a string, so [xs] is a list containing a string, which isn't what you want. This is fixed by removing the square brackets.
Possibly the ordering of the reduction is wrong.
On a different note, the duplicated if statement suggests that there is some optimisations that could happen with your code. Specifically, if you handle the empty string as part of negbin_dezi then you won't have to special case it. You could write it something like
negbin_dezi "" _ = 0
negbin_dezi (x:xs) n
| n == '0' = negbin_dezi xs (n+1)
| n == '1' = (-2)^n + negbin_dezi
(This has the bonus of meaning that the function is "more total", i.e. it is defined on more inputs.)
A few more things:
The code is "stringly-typed": your data is being represented as a string, despite having more structure. A list of booleans ([Bool]) would be much better.
The algorithm can be adapted to be cleaner. For the following, I'm assuming you are storing it like "01" = -2 "001" = 4, etc. If so, then we know that number = a + (-2) * b + (-2)^2 * c ... = a + (-2) * (b + (-2) * (c + ...)) where a,b,c,... are the digits. Looking at this, we can see the stuff inside the brackets is actually the same as the whole expression, just starting at the second digit. This is easy to express in Haskell (I'm using the list-of-bools idea.):
negbin [] = 0
negbin (x:xs) = (if x then 1 else 0) + (-2) * negbin xs
And that's the whole thing. If you aren't storing it in that order, then a call to reverse fixes that! (Being really tricky, one could write
negbin = foldr (\x n -> (if x then 1 else 0) + (-2)*n) 0
)
Some problems:
x == 0 or x == 1, but x is a Char, so you mean x == '0'.
You write (xs:x). There's no pattern for matching at the end of a list. Perhaps use a helper function that reverses the list first.
[xs] has one element, and will never be "". Use a base case instead.
Pattern matching is more helpful than equality checking.
** is for floating point powers, ^ is for integer powers
You often use [xs] where you mean xs. You don't need to put square brackets to make a list.
Here's a rewrite that works:
negbin_dezi1 :: NegaBinary -> Integer
negbin_dezi1 xs = negbin (reverse xs) 0
negbin [] _ = 0
negbin (x:xs) n
| x == '0' = negbin xs (n+1)
| x == '1' = (-2)^n + (negbin xs (n+1))
It would be nicer to use pattern matching:
negbin_dezi2 :: NegaBinary -> Integer
negbin_dezi2 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin ('0':xs) n = negbin xs (n+1)
negbin ('1':xs) n = (-2)^n + negbin xs (n+1)
But maybe it would be nicer to convert '0' to 0 and '1' to 1 and just multiply by that:
val :: Char -> Int
val '0' = 0
val '1' = 1
negbin_dezi3 :: NegaBinary -> Integer
negbin_dezi3 xs = negbin (reverse xs) 0 where
negbin [] _ = 0
negbin (x:xs) n = val x * (-2)^n + negbin xs (n+1)
I'd not write it that way, though:
A completely different approach is to think about the whole thing at once.
"10010" -rev> [0,1,0,0,1] -means> [ 0, 1, 0, 0, 1 ]
[(-2)^0, (-2)^1, (-2)^2, (-2)^3, (-2)^4]
so let's make both lists
powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
and multiply them
zipWith (*) powers coefficients
then add up, giving:
negbin_dezi4 xs = sum $ zipWith (*) powers coefficients
where powers = [(-2)^n | n <- [0..]]
coefficients = reverse.map val $ xs
You could rewrite powers as map ((-2)^) [0..],
or even nicer: powers = 1:map ((-2)*) powers.
(It's nicer because it reuses previous calculations and is pleasantly clean.)
this
convB2D::NegaBinary->Integer
convB2D xs|(length xs)==0 =0
|b=='0' = convB2D(drop 1 xs)
|b=='1' = val+convB2D(drop 1 xs)
|otherwise= error "invalid character "
where b=head xs
val=(-2)^((length xs)-1)
worked for me.
I on the other hand have problems to convert dec->nbin :D

Resources