Attempting to convert ints into strings in haskell - haskell

I am attempting to write a code to take in an integer and output that integer in words. Ex: if the input is 4321 the output is four thousand three hundred twenty one.
For this, I would first like to break the input into it's individual digits. ex input 4321 would become an array of [4,3,2,1].
My current code
newtype wordInt = WI Int
instance Show WordInt where
show (WI x) | x>= 0 = helper x
| x < 0 = helper -x
helper 0 = [0]
helper x = x `mod` 10 : helper (x `div` 10)
At the moment, I think i'm getting a type error.
Please note that this needs to be able to hand both positive and negative numbers. Also, if you can think of an efficient way to do the conversion i'm looking for, it would be much appreciated.

Names of types cannot begin with a lowercase letter. Change wordInt to WordInt here:
newtype wordInt = WI Int
The method show of the Show class must return a String and your helper has the type Int -> [Int] (when applied to an Int). You need to somehow convert the list into a String, for instance by calling show on the list:
instance Show WordInt where
show (WI x) | x >= 0 = show $ helper x
| x < 0 = show $ helper (-x)
Finally, notice that I put -x in parentheses. This is needed for unary minus because otherwise the compiler will think you are trying to subtract x from helper (which is a function and not an Int).
However, your implementation of helper is wrong because it returns the list of digits in reverse. To fix this, you can write a helper function to split the digits and then reverse the list:
helper :: Int -> [Int]
helper = reverse . go
where go 0 = [0]
go x = x `mod` 10 : go (x `div` 10)
However, this will pad the number with a leading zero:
λ. helper 4321
[0,4,3,2,1]
This doesn't change the meaning, of course, but if it is a problem, write a wrapper function to deal with this case:
helper :: Int -> [Int]
helper x =
case splitIntoDigits x of
[] -> [0]
xs -> reverse xs
splitIntoDigits :: Int -> [Int]
splitIntoDigits 0 = []
splitIntoDigits x = x `mod` 10 : splitIntoDigits (x `div` 10)
It then works in both cases:
λ. helper 0
[0]
λ. helper 4321
[4,3,2,1]

Related

How to break a number into a list of digits? [duplicate]

Given an arbitrary number, how can I process each digit of the number individually?
Edit
I've added a basic example of the kind of thing Foo might do.
For example, in C# I might do something like this:
static void Main(string[] args)
{
int number = 1234567890;
string numberAsString = number.ToString();
foreach(char x in numberAsString)
{
string y = x.ToString();
int z = int.Parse(y);
Foo(z);
}
}
void Foo(int n)
{
Console.WriteLine(n*n);
}
Have you heard of div and mod?
You'll probably want to reverse the list of numbers if you want to treat the most significant digit first. Converting the number into a string is an impaired way of doing things.
135 `div` 10 = 13
135 `mod` 10 = 5
Generalize into a function:
digs :: Integral x => x -> [x]
digs 0 = []
digs x = digs (x `div` 10) ++ [x `mod` 10]
Or in reverse:
digs :: Integral x => x -> [x]
digs 0 = []
digs x = x `mod` 10 : digs (x `div` 10)
This treats 0 as having no digits. A simple wrapper function can deal with that special case if you want to.
Note that this solution does not work for negative numbers (the input x must be integral, i.e. a whole number).
digits :: Integer -> [Int]
digits = map (read . (:[])) . show
or you can return it into []:
digits :: Integer -> [Int]
digits = map (read . return) . show
or, with Data.Char.digitToInt:
digits :: Integer -> [Int]
digits = map digitToInt . show
the same as Daniel's really, but point free and uses Int, because a digit shouldn't really exceed maxBound :: Int.
Using the same technique used in your post, you can do:
digits :: Integer -> [Int]
digits n = map (\x -> read [x] :: Int) (show n)
See it in action:
Prelude> digits 123
[1,2,3]
Does that help?
You could also just reuse digits from Hackage.
Textbook unfold
import qualified Data.List as L
digits = reverse . L.unfoldr (\x -> if x == 0 then Nothing else Just (mod x 10, div x 10))
You can use
digits = map (`mod` 10) . reverse . takeWhile (> 0) . iterate (`div` 10)
or for reverse order
rev_digits = map (`mod` 10) . takeWhile (> 0) . iterate (`div` 10)
The iterate part generates an infinite list dividing the argument in every step by 10, so 12345 becomes [12345,1234,123,12,1,0,0..]. The takeWhile part takes only the interesting non-null part of the list. Then we reverse (if we want to) and take the last digit of each number of the list.
I used point-free style here, so you can imagine an invisible argument n on both sides of the "equation". However, if you want to write it that way, you have to substitute the top level . by $:
digits n = map(`mod` 10) $ reverse $ takeWhile (> 0) $ iterate (`div`10) n
Via list comprehension:
import Data.Char
digits :: Integer -> [Integer]
digits n = [toInteger (digitToInt x) | x <- show n]
output:
> digits 1234567890
[1,2,3,4,5,6,7,8,9,0]
I was lazy to write my custom function so I googled it and tbh I was surprised that none of the answers on this website provided a really good solution – high performance and type safe. So here it is, maybe somebody would like to use it. Basically:
It is type safe - it returns a type checked non-empty list of Word8 digits (all the above solutions return a list of numbers, but it cannot happen that we get [] right?)
This one is performance optimized with tail call optimization, fast concatenation and no need to do any reversing of the final values.
It uses special assignment syntax which in connection to -XStrict allows Haskell to fully do strictness analysis and optimize the inner loop.
Enjoy:
{-# LANGUAGE Strict #-}
digits :: Integral a => a -> NonEmpty Word8
digits = go [] where
go s x = loop (head :| s) tail where
head = fromIntegral (x `mod` 10)
tail = x `div` 10
loop s#(r :| rs) = \case
0 -> s
x -> go (r : rs) x
Here's an improvement on an answer above. This avoids the extra 0 at the beginning ( Examples: [0,1,0] for 10, [0,1] for 1 ). Use pattern matching to handle cases where x < 10 differently:
toDigits :: Integer -> [Integer] -- 12 -> [1,2], 0 -> [0], 10 -> [1,0]
toDigits x
| x < 10 = [x]
| otherwise = toDigits (div x 10) ++ [mod x 10]
I would have put this in a reply to that answer, but I don't have the needed reputation points :(
Applicative. Pointfree. Origami. Neat.
Enjoy:
import Data.List
import Data.Tuple
import Data.Bool
import Control.Applicative
digits = unfoldr $ liftA2 (bool Nothing) (Just . swap . (`divMod` 10)) (> 0)
I've been following next steps(based on this comment):
Convert the integer to a string.
Iterate over the string
character-by-character.
Convert each character back to an integer,
while appending it to the end of a list.
toDigits :: Integer -> [Integer]
toDigits a = [(read([m])::Integer) | m<-show(a)]
main = print(toDigits(1234))
For returning a list of [Integer]
import Data.Char
toDigits :: Integer -> [Integer]
toDigits n = map (\x -> toInteger (digitToInt x)) (show n)
The accepted answer is great but fails in cases of negative numbers since mod (-1) 10 evaluates to 9. If you would like this to handle negative numbers properly... which may not be the case the following code will allow for it.
digs :: Int -> [Int]
digs 0 = []
digs x
| x < 0 = digs ((-1) * x)
| x > 0 = digs (div x 10) ++ [mod x 10]
The accepted answer is correct except that it will output an empty list when input is 0, however I believe the output should be [0] when input is zero.
And I don't think it deal with the case when the input is negative. Below is my implementation, which solves the above two problems.
toDigits :: Integer -> [Integer]
toDigits n
| n >=0 && n < 10 = [n]
| n >= 10 = toDigits (n`div`10) ++ [n`mod`10]
| otherwise = error "make sure your input is greater than 0"
I would like to improve upon the answer of Dave Clarke in this page. It boils down to using div and mod on a number and adding their results to a list, only this time it won't appear reversed, nor resort to ++ (which is slower concatenation).
toDigits :: Integer -> [Integer]
toDigits n
| n <= 0 = []
| otherwise = numToDigits (n `mod` 10) (n `div` 10) []
where
numToDigits a 0 l = (a:l)
numToDigits a b l = numToDigits (b `mod` 10) (b `div` 10) (a:l)
This program was a solution to a problem in the CIS 194 course at UPenn that is available right here. You divide the number to find its result as an integer and the remainder as another. You pass them to a function whose third argument is an empty list. The remainder will be added to the list in case the result of division is 0. The function will be called again in case it's another number. The remainders will add in order until the end.
Note: this is for numbers, which means that zeros to the left won't count, and it will allow you to have their digits for further manipulation.
digits = reverse . unfoldr go
where go = uncurry (*>) . (&&&) (guard . (>0)) (Just . swap . (`quotRem` 10))
I tried to keep using tail recursion
toDigits :: Integer -> [Integer]
toDigits x = reverse $ toDigitsRev x
toDigitsRev :: Integer -> [Integer]
toDigitsRev x
| x <= 0 = []
| otherwise = x `rem` 10 : toDigitsRev (x `quot` 10)

Using fold* to grow a list in Haskell

I'm trying to solve the following problem in Haskell: given an integer return the list of its digits. The constraint is I have to only use one of the fold* functions (* = {r,l,1,l1}).
Without such constraint, the code is simple:
list_digits :: Int -> [Int]
list_digits 0 = []
list_digits n = list_digits r ++ [n-10*r]
where
r = div n 10
But how do I use fold* to, essentially grow a list of digits from an empty list?
Thanks in advance.
Is this a homework assignment? It's pretty strange for the assignment to require you to use foldr, because this is a natural use for unfoldr, not foldr. unfoldr :: (b -> Maybe (a, b)) -> b -> [a] builds a list, whereas foldr :: (a -> b -> b) -> b -> [a] -> b consumes a list. An implementation of this function using foldr would be horribly contorted.
listDigits :: Int -> [Int]
listDigits = unfoldr digRem
where digRem x
| x <= 0 = Nothing
| otherwise = Just (x `mod` 10, x `div` 10)
In the language of imperative programming, this is basically a while loop. Each iteration of the loop appends x `mod` 10 to the output list and passes x `div` 10 to the next iteration. In, say, Python, this'd be written as
def list_digits(x):
output = []
while x > 0:
output.append(x % 10)
x = x // 10
return output
But unfoldr allows us to express the loop at a much higher level. unfoldr captures the pattern of "building a list one item at a time" and makes it explicit. You don't have to think through the sequential behaviour of the loop and realise that the list is being built one element at a time, as you do with the Python code; you just have to know what unfoldr does. Granted, programming with folds and unfolds takes a little getting used to, but it's worth it for the greater expressiveness.
If your assignment is marked by machine and it really does require you to type the word foldr into your program text, (you should ask your teacher why they did that and) you can play a sneaky trick with the following "id[]-as-foldr" function:
obfuscatedId = foldr (:) []
listDigits = obfuscatedId . unfoldr digRem
Though unfoldr is probably what the assignment meant, you can write this using foldr if you use foldr as a hylomorphism, that is, building up one list while it tears another down.
digits :: Int -> [Int]
digits n = snd $ foldr go (n, []) places where
places = replicate num_digits ()
num_digits | n > 0 = 1 + floor (logBase 10 $ fromIntegral n)
| otherwise = 0
go () (n, ds) = let (q,r) = n `quotRem` 10 in (q, r : ds)
Effectively, what we're doing here is using foldr as "map-with-state". We know ahead of time
how many digits we need to output (using log10) just not what those digits are, so we use
unit (()) values as stand-ins for those digits.
If your teacher's a stickler for just having a foldr at the top-level, you can get
away with making go partial:
digits' :: Int -> [Int]
digits' n = foldr go [n] places where
places = replicate num_digits ()
num_digits | n > 0 = floor (logBase 10 $ fromIntegral n)
| otherwise = 0
go () (n:ds) = let (q,r) = n `quotRem` 10 in (q:r:ds)
This has slightly different behaviour on non-positive numbers:
>>> digits 1234567890
[1,2,3,4,5,6,7,8,9,0]
>>> digits' 1234567890
[1,2,3,4,5,6,7,8,9,0]
>>> digits 0
[]
>>> digits' 0
[0]
>>> digits (negate 1234567890)
[]
>>> digits' (negate 1234567890)
[-1234567890]

Convert binary string to integer value using first order functions

Given a finite list of 0 and 1, how can I convert them to their integer value using first order function?
The head of the list is the least significant digit. For instance, 1011 evaluates to 13.
In this problem, I struggle to find both the recursive step and the base step because all depends wether it's a 0 and 1.
EDIT :
The goal is to define a function that will compute the decimal value given a binary string. An empty list should return 0 I guess, so it would be the base case.
Wrapping up my comments:
convert :: [Int] -> Int
convert [] = 0
convert (x : xs) = x + 2 * convert xs
The base case is the empty list, returning 0.
The recursive case follows from the fact that x is the least significant digit. convert xs (the recursive call) gives us the result for the tail of the list; to get the result of the whole list we need to multiply by 2 (to "shift over" the digits) and add x (0 or 1).
Here's my initial thoughts about how to handle this situation.
import Data.Char (digitToInt)
myFunction :: String -> Int
myFunction = foldr step 0
where step x y = (+) (digitToInt x) ( (*) y 2 )
Assuming the input is a list of 1s and 0s.
bin2num :: [Int] -> Int
bin2num list = go list 0
where go [] _ = 0
go (x:xs) n = (x*(2^n)) + (go xs (n+1))
Just double the acc and add it to the new element of the list . Easily use digitToInt to get the right list from the string _ st here . and foldl' for efficiency. This is Sanaz's answer
fromBin st = foldl' (\x acc -> x * 2 + acc ) 0 (map (digitToInt) st)

How can I create non-repeating palindromic numbers?

So I'm trying to do something and it's almost there I think but I can't solve the last part of it. I have to make a code where someone gives a number (let's make it 22) an I need to find all the palindromic numbers there is when I multiply two numbers smaller than 22:
Find all the palindromic numbers of a*b but a < n && b < n. but they can't repeat themselves.
I got this
calc :: Int -> [Int]
calc n = [a*b|a<-[1..n-1], b<-[a..n-1], a*b>10, reverse(show(a*b))==show(a*b)]
If we do calc 22 the result should be
[11,22,33,44,55,66,77,88,99,171,121,252,272,323]
but I'm getting
[11,22,33,44,55,66,77,88,99,171,121,252,252,272,323]
because 14x18 = 12x21 = 252.
Where did I go wrong?
Well, you have to make sure that every number is unique. There exist multiple representations for all numbers with at least three prime factors (x * y * z = (x * y) * z = x * (y * z)). So one way we could tacke this would be prime factor analysis and reasoning about them. But that's probably an overkill.
Instead, we can use a function that makes sure that every number in our sorted list is unique:
unique :: Eq a => [a] -> [a]
unique (x:y:xs) = if x == y then unique (y:xs) else x : unique (y:xs)
unique xs = xs
(Alternatively, use unique = map head . group)
Now you can use sort from Data.List and you end up with your actual calUniuqe:
calcUnique :: Int -> [Int]
calcUnique = unique . sort . calc
However, we can make calc a lot easier to read if we move the palindrome check into its own function:
isPalindrome :: Int -> Bool
isPalindrome n = n > 10 && reverse n' == n'
where n' = show n
calc :: Int -> [Int]
calc n = [a * b | a <- [1..n-1], b <- [a..n-1], isPalindrome (a * b)]

Convert Int into [Int]

I'm looking through a past exam paper and don't understand how to convert Int to [Int].
For example, one of the questions asks us to produce a list of all the factors of a whole number excluding both the number itself and 1.
strictFactors Int -> [Int]
strictFactors x = ???
I'm not asking for anyone to do this question for me! I just want to know how I'd convert an integer input to a list of integer output. Thanks!
Perhaps it would be easiest to have a look at some similar code. As requested, I won't give you the answer, but you should be able to use these ideas to do what you want.
Brute force
Here we're just going to use all the pairs of numbers between 1 and x to test if we can make x as the sum of two square numbers:
sumOfSquares :: Int -> [Int]
sumOfSquares x = [ (a,b) | a <- [1..x], b <- [a..x], a^2 + b^2 == x]
You call this like this:
ghci> asSumOfSquares 50
[(1,7),(5,5)]
because 50 = 1^2+7^2 and also 50 = 5^2 + 5^2.
You can think of sumOfSquares as working by first taking an a from the list [1..x] of numbers between 1 and x and then another between that and x. It then checks a^2 + b^2 == x. If that's True, it adds (a,b) to the resulting list.
Generate and check
This time let's generate some single numbers then check whether they're a multiple of another. This will calculate the least common multiple (lcm). For example, the least common multiple of 15 and 12 is 60, because it's the first number that's in both the 15 and 12 times tables.
This function isn't of the type you want but it uses all the techniques you want.
lcm :: Int -> Int -> Int
lcm x y = head [x*a | a <- [1..], (x*a) `mod` y == 0]
You can call that like this:
ghci> lcm 12 15
60
This time the list of numbers [1..] is (in principle) infinite; good job we're just picking the first one with head!
(x*a) `mod` y == 0 does the checking to see whether the number x*a is a multiple of y (mod gives the remainder after division). That's a key idea you should use.
Summary
Use a <- [1..end] to generate numbers, test them with a True/False expression (i.e. a Bool), perhaps using the mod function.
I'm quite new at Haskell but can think of a myriad ways of "converting" an Int to a list containing that same Int:
import Control.Applicative (pure)
sane_lst :: Int -> [Int]
sane_lst x = [x]
lst :: Int -> [Int]
lst x = take 1 $ repeat x
lst' :: Int -> [Int]
lst' = replicate 1
lst'' :: Int -> [Int]
lst'' = return
lst''' :: Int -> [Int]
lst''' = pure
lst'''' :: Int -> [Int]
lst'''' x = enumFromTo x x
I guess the point here is that you don't "convert" to a list, you rather "construct" the list you need. The staightforward strategy for the kind of question you posed is to find something that will give you a suitable starting list to work with based on your parameter, then filter, fold or comprehend as needed.
For example when I say:
lst x = take 1 $ repeat x
I'm first constructing an infinite list repeating the value I passed in, and then taking from it a list containing just the first element. So if you think about what kind of list you need to start with to find the solution to your problem you'll be halfway there.
If your only goal is to convert between the types (for now) then strictFactors x = [x] is the most canonical answer. This function is also called pure since [] is what's known as an Applicative and return since [] is known as a Monad.

Resources