Haskell Code Problem
Description: Code is supposed to return how many digits in the number divide the number as a whole.
For example, 12 has two digits [1, 2], both of which divide 2 (12%2 and 12%1 are both 0) so 2 is returned as there are two digits that divide the number.
For 102, 2 is returned as 1 and 2 both divide 102, division by 0 is undefined.
However, with this code I get errors with numbers containing 0s in the middle of the number (e.g. 1001020)
I get "Program Error: Prelude.read: no parse"
Any help will be greatly appreciated. Many thanks.
import Control.Monad
import Data.Array
import Data.Bits
import Data.Char
import Data.List
import Data.Set
import Debug.Trace
import System.Environment
import System.IO
import System.IO.Unsafe
findDigits :: Int -> Int
findDigits n = digits n n 0 (lengths n)
where
digits n on count endCheck
| endCheck == 0 = count
| header n == 0 = digits (tailer n) on count (endCheck-1)
| on `mod` header n == 0 = digits (tailer n) on (count+1) (endCheck-1)
| otherwise = digits (tailer n) on count (endCheck-1)
header :: Int -> Int
header x = digitToInt . head . show $ x
tailer :: Int -> Int
tailer x = read . tail . show $ x
lengths :: Int -> Int
lengths x = length . show $ x
I think you are trying to do too much in a function. Uually it is better to work with small functions that each solve a simple task, and then combine these in functions that are small as well, and perform a (slightly) more sophisticated task.
For example we can make a function digits :: Int -> [Int] that returns a list of digits:
digits :: Int -> [Int]
digits x | x >= 10 = r : digits q
| otherwise = [x]
where (q,r) = quotRem x 10
For example:
Prelude> digits 102
[2,0,1]
We can then filter these digits to check that the digits are not zero (since then it is not dividable), and that the number is dividable by that digit:
dividableDigits :: Int -> [Int]
dividableDigits n = filter (\x -> x /= 0 && mod n x == 0) (digits n)
Now it is a matter of counting the numbers that match. I leave that as an exercise.
Related
I'm tasked with writing a Haskell program that'll prompt the user to input a string, and then the program will assign a number to each letter(e.g. a = 1, d = 4, y = 25, z = 26) and then it will sum the total from the string. Example "Hi" would equal 8 + 9 or 17. I've got something to do the first part but only if its in all caps, but I still can't figure out how to get the output list summed.
import Data.Char
toOrder :: [Char] -> [Int]
toOrder str = map ((\x -> x - 64) . ord) str
Ideas?
You can use toUpper to regularize the characters, and sum to sum the list of Ints:
import Data.Char (ord, toUpper)
main = print $ score "Hi" -- 17
score :: String -> Int
score = sum . map (subtract 64 . ord . toUpper)
I use recursion to compare two numbers(ex 123 is the same with 123) and store how many digits they have in common(ex 123 compared to 123 has 3 and with 124 has 2).
While my program does find that number i want to put conditions for every situation (ex if they have 2 digits in common output value 44 or if they have 3 do something else etc.) but no comparison is done. Can someone please explain to me what and why that happens. Here my code :
dg :: Int->Int->Int
dg 0 0 = 0
dg x y = if (c==2) then 23 else 24 -- c = common digits
where c = digits (x `div` 10) (y `div` 10) + if (x `mod` 10 == y `mod` 10) then 1 else 0
I run hugs deleting the "if" condition, giving input 10 10 the output is 2 but when i leave it on and rerun it, it goes to 24 (while 23 is correct). I'm really confused.
To find how many digits two Int have in common, using the string representation isn't too bad (It's actually terrible, see update below).
commonDigits :: Int -> Int -> Int
commonDigits a b = length . filter id $ zipWith (==) (reverse $ show a) (reverse $ show b)
reverse is needed to make sure the digits align properly.
If you're into point-free style:
import Data.Function
commonDigits :: Int -> Int -> Int
commonDigits = fmap (length . filter id) . zipWith (==) `on` reverse . show
Then if you want to return a special Int depending on the result of commonDigits you can use a separate function:
specialResult :: Int -> Int -> Int
specialResult a b =
case commonDigits a b of
2 -> 23
3 -> 48
_ -> 256
Update: For negative integers this method is not good. If only one of the argument is negative this function should behave like your mod 10 version. If both are negative there is the possibility that the '-' sign is counted as a digit.
Let's use a digits function that will give a list of digits for both positive and negative numbers from the least significant to the most significant digits. What happens if the number 0 is given as input, should we return an empty list or [0]? Your call on that one, but I'm going to assume you want [0].
digits :: Int -> [Int]
digits 0 = [0]
digits n = digits' (abs n)
where
digits' 0 = []
digits' n = n `mod` 10 : digits' (n `div` 10)
With this new digits function we can rewrite commonDigits to:
commonDigits :: Int -> Int -> Int
commonDigits = fmap (length . filter id) . zipWith (==) `on` digits
I am working on a program to get the closest prime number by the exponent of 2, this is between an interval.
module Main where
import Data.Char
import System.IO
import Control.Monad (liftM)
data PGetal = G Bool | P Int
instance Show PGetal where
show (P n) = show n
show (G False) = "GEEN PRIEMGETAL GEVONDEN"
mPriem::(Int, Int) -> PGetal
mPriem (x,y) | (x > y) = G False
| (x > 1000000) = G False
| (y > 1000000) = G False
| (null (getAllPriem(x,y))) = G False
| otherwise = P (kleinsteVerschilF(getAllPriem(x,y),1000000,1))
kleinsteVerschilF:: ([Int], Int , Int) -> Int
kleinsteVerschilF ([],_, priemGetal) = priemGetal
kleinsteVerschilF (priem1:priemcss, kleinsteVerschil,priemGetal)=
if(kleinsteVerschil <= kleinsteVerschilMetLijst (priem1,(getMachtenVanTwee(0)),1000000))then kleinsteVerschilF(priemcss, kleinsteVerschil,priemGetal)
else kleinsteVerschilF (priemcss,kleinsteVerschilMetLijst(priem1,(getMachtenVanTwee(0)),1000000), priem1)
kleinsteVerschilMetLijst :: (Int,[Int],Int) -> Int
kleinsteVerschilMetLijst ( _,[],kleinsteVerschil) = kleinsteVerschil
kleinsteVerschilMetLijst (x,tweeMachten1:tweeMachtencss,kleinsteverschil)=
if((abs(x-tweeMachten1)) < kleinsteverschil)
then kleinsteVerschilMetLijst(x,tweeMachtencss, (abs(x-tweeMachten1)))
else kleinsteVerschilMetLijst(x,tweeMachtencss, kleinsteverschil)
getAllPriem :: (Int, Int) ->[Int]
getAllPriem (x,y) = filter isPriem [x..y]
getMachtenVanTwee ::(Int) -> [Int]
getMachtenVanTwee (macht)
|(functieMachtTwee(macht)< 1000000) = (functieMachtTwee(macht)) : (getMachtenVanTwee ((macht+1)))
| otherwise = []
functieMachtTwee:: (Int) -> Int
functieMachtTwee (x) = 2^x
isPriem n = (aantalDelers n)==2
aantalDelers n = telAantalDelersVanaf n 1
telAantalDelersVanaf n kandidaatDeler
| n == kandidaatDeler = 1
| mod n kandidaatDeler == 0
= 1 + telAantalDelersVanaf n (kandidaatDeler+1)
| otherwise
= telAantalDelersVanaf n (kandidaatDeler+1)
aantalDelers2 getal = telDelers getal 1 0
where telDelers n kandidaat teller
| n == kandidaat = 1+teller
| mod n kandidaat == 0
= telDelers n (kandidaat+1) (teller+1)
| otherwise
= telDelers n (kandidaat+1) teller
transform :: [String] -> [PGetal]
transform [] = []
transform (cs:css) =
let (a : b: _ ) = words cs
in (mPriem ((read(a)),(read(b))): transform css)
main :: IO ()
main = do
n <- read `liftM` getLine :: IO Int
lss <- lines `liftM` getContents
let cases = take n lss
let vs = (transform (lss))
putStr $ unlines $ map show vs
When I use the mPriem function, it works fine.
But it needs to work with an input txt file, so I made a .exe file with the ghc command. I also added this .txt file in the folder.
10
1 1
1 3
1 100
200 250
14 16
5 10
20 31
16 50
100 120
5200 7341
When I use in command line this command, it does nothing. There is no output. I can't CTRL+C to stop the program, so I think it crashes. But I don't know what's wrong.
type invoer.txt | programma.exe
Your program works, but is not that efficient and personally I find it not that elegant (sorry :S) because you introduce a lot of "noise". As a result it takes a lot of time before output is written.
If I understand the problem statement correctly, each line (except the first), contains two integers, and you need to count the amount of prime numbers between these two numbers (bounds inclusive?)
First of all, you can do this more elegantly by defining a function: cPrime :: Int -> Int -> Int that takes as input the two numbers and returns the amount of prime numbers:
cPrime :: Int -> Int -> Int
cPrime a b = count $ filter isPrime [a .. b]
You can improve performance by improving your prime checking algorithm. First of all, you do not need to check whether 1 is a divisor, since 1 is always a divisor. Furthermore, you can prove mathematically that there is no divisor greater than sqrt(n) (except for n) that divides n; unless there is another divider that is smaller than sqrt(n). So that means that you can simply enumerate all numbers between 2 and sqrt n and from the moment one of these is a divisor, you can stop: you have proven the number is not prime:
isPrime :: Int -> Bool
isPrime 1 = False
isPrime 2 = True
isPrime n = all ((0 /=) . mod n) (2:[3,5..m])
where m = floor $ sqrt $ fromIntegral n
Now I'm not sure what you aim to do with kleinsteVerschilF.
I am trying to get a function that returns a list of lists of zeros or ones, obviously in a random way.
Example:
getBinaryRandomList::Int->Int->[[Int]]
Prelude> getBinaryRandomList 4 3
[[1,0,0,1],[1,1,0,1],[0,0,0,1], [0,1,0,1]]
So far, i have done this functions:
--tuns an `Int` into a `[Int]`. The [Int] would represent a binary number
int2bin :: Int -> [Int]
int2bin 0 = []
int2bin n = mod n 2 : int2bin (div n 2)
I have got stuck here, it throws an error at compilation time:
--returns a random number
import System.Random
randomInt::(Int,Int)->Int
randomInt x y = do
newStdGen
randomR(x, y) getStdGen
Compiling...
[1 of 1] Compiling Main ( ag.hs, interpreted )
ag.hs:8:25: parse error on input `randomR'
The "main" function would be like this:
--n lists number
--d digit number
getBinaryRandomList::Int->Int->[[Int]]
getBinaryRandomList d 0 = []
getBinaryRandomList d n = take d (int2bin(randomInt(0,50))) : getBinaryRandomList(n-1)
My approach is the next:
Coding a function that creates an aleatory Int number between 0 an n.
randomInt::(Int,Int)->Int
Coding a function that converts those aleatory numbers into a list of binaries.
int2bin::Int->[Int] % Already done
Forming a list with those numbers
getBinaryRandomList::Int->Int->[[Int]]
How could I implement that in Haskell?
As it was pointed out in a comment, you can't create a StdGen without IO, but you can create one in your main function and pass it along in a parameter to your randomInt function, in this way:
import System.Random
main = do
a <- newStdGen
putStrLn . show . randomInt 0 1 $ a
randomInt:: Int -> Int -> StdGen -> (Int, StdGen)
randomInt x y s = do
randomR (x, y) s
The error message that you got about RandomR was caused by not importing System.Random.
I hope this helps.
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)