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.
I have the following function:
digits :: Int -> [Int]
digits n = go n []
where go num acc
| num < 10 = num : acc
| otherwise = go (div num 10) (mod num 10 : acc)
Is it possible to replace the parentheses in the otherwise expression with $?
The problem
You can't use $ for that. The purpose of $ is to make function application bind as un-tighly as possible, as opposed to normal function application which binds most tightly,
> :i $
($) :: (a -> b) -> a -> b
infixr 0 $
(some irrelevant stuff removed...)
Here, infixr denotes that the operator is right associative, as opposed to infixl which denotes that the operator is left associative. 0 denotes the precedence of the operator. 0 binds least tightly and 9 binds most tightly.
If we write go $ div num 10 $ mod num 10 : acc, this is interpreted as go (div num 10 (mod num 10 : acc)), i.e: passing mod num 10 : acc as the third argument of div, and the result of applying div as the only argument to go.
Solution: the (&) operator
Instead of using the dollar sign, $, for the left hand side, you can instead use &.
> :i &
(&) :: a -> (a -> b) -> b -- Defined in `Data.Function'
infixl 1 &
And now we get:
import Data.Function ((&))
digits :: Int -> [Int]
digits n = go n []
where go num acc
| num < 10 = num : acc
| otherwise = div num 10 & go $ mod num 10 : acc
Solution: apply go infix
You could also use go infix:
digits :: Int -> [Int]
digits n = go n []
where go num acc
| num < 10 = num : acc
| otherwise = div num 10 `go` (mod num 10 : acc)
In this case, the parenthesis on the right hand side is needed due to (:) which is also infix and interferes with go.
Which solution to use
In my opinion, if you can use infix application without parenthesizes, do that. In the case of having a parenthesis on any side such as in: div num 10 `go` (mod num 10 : acc), it may still be warranted to use infix. This is mainly due to readability, as the average reader may not be familiar with &. This notation is (probably) not very commonly used, which is why the average reader is not very familiar with it (and so we have a cycle...).
On the usage of $$
I believe Alexey Romanov's operator, $$ is quite neat as well. Unfortunately, it suffers the same problems as & does: lack of familiarity. Hopefully, his operator can be added to Data.Function in due time and perhaps we can expand our toolbox.
In addition to the answers #Centril mentions, you can replace only the second pair:
go (div num 10) $ mod num 10 : acc
or both, but then you need parentheses in a different place:
(go $ div num 10) $ mod num 10 : acc
or declare another operator like $ but left-associative:
f $$ x = f x
infixl 0 $$
go $$ div num 10 $$ mod num 10 : acc
Please help, I've been trying to get this code to work but I can't find the errors. Below is my code
sumToN f x 1 = f (x 1)
sumToN f x n = f x n + f x (n-1)
facOfN 0 = 1
facOfN n = n * facOfN (n-1) sgfr
sineApprox x n = ((-1) ^ n) * ((x ** (2*n+1))/facOfN(2*n+1)
sine x n = sumToN (sineApprox x n)
When I try to load the file I get the following error.
ERROR file:F:\sine.hs:8 - Syntax error in expression (unexpected `;', possibly due to bad layout)
Any assistance would be greatly appreciated.
As already said in the comments, you've forgotten to close a paren. It'll work like that:
sineApprox x n = ((-1) ^ n) * ((x ** (2*n+1))/facOfN(2*n+1))
Note that this problem would have been obvious with a better text editor. Being a beginner, I suggest you switch to iHaskell, which has a very simple interface and yet reasonably powerful editor features.
The problem would also have been obvious if you hadn't used so many unnecessary parens. The following can be omitted just like that, some can be replaced with $. While we're at style...
sumToN f x n -- checking ==1 is not safe in general
| n<=1 = f $ x 1
| otherwise = f x n + f x (n-1)
facOfN = product [1..n]
sineApprox x n = (-1)^n * x**(2*n+1) / facOfN (2*n+1)
sine x = sumToN . sineApprox x
On another note: in general, you should always use type signatures. This code actually has problems because all the counter variables are automaticall floating point (like everything else). They should really be Ints, which requires a conversions in the factorial†:
sumToN :: Num n => (Int -> n) -> Int -> n
sumToN f x n
| n<1 = 0
| otherwise = f x n + f x (n-1)
facOfN :: Num n => Int -> n
facOfN = product [1 .. fromIntegral n]
sineApprox :: Fractional n => n -> Int -> n
sineApprox x n = (-1)^n * x^(2*n+1) / facOfN (2*n+1)
sine
sine x = sumToN . sineApprox x
†BTW, explicitly using factorials is almost always a bad idea, as the numbers quickly get intractibly huge. Also, you're doing a lot of duplicate work. Better multiply as you add along!
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)
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)