Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- Let's see what Wolfram Alpha has for us:
- > RTA is the sequence obtained from reversing the digits of a number _n_ and adding the result to the original number.
- > The 196-algorithm operates RTA iteratively until a palyndromic number is obtained.
- Let's define alg196 then. We can take the definition above literally and get the following script:
- ```hs
- alg196 :: Integer -> [Integer]
- alg196 n = takeWhile palyndromic . rtaseq n
- ```
- `rtaseq` will produce an infinite stream of numbers, but we only care about those up to the first that is palyndromic.
- Essentially we want to produce the sequence
- ```hs
- rtaseq n = n : n2 : n3 : n4 : ...
- where n2 = n + reverse n
- n3 = n2 + reverse n2
- n4 = n3 + reverse n3
- ...
- ```
- We notice that each element of the list depends on the previous one. There are many ways to express that in Haskell, but
- one that really shines is via _cyclic lists_. If I were to define the list `[1, 2, 3, 4, ...]`, I could say that it is the
- list that starts with `1` followed by the list itself where every element is added to 1.
- ```hs
- plus1 = 1 : fmap (+1) plus1
- ```
- In our case, we need to take each number, reverse it, and add it to itself. This can be expressed just as easily by summing
- pair-wise the elements of the list itself with the elements of the list "mirrored", i.e. where the digits have been reversed:
- ```hs
- rtaseq n = ns where ns = n : zipWith (+) ns (fmap mirror ns)
- ```
- The `mirror` function can be described in a two-step process: first get the digits, then reassemble them in reverse order.
- ```hs
- mirror :: Integer -> Integer
- mirror = undigits . digits
- ```
- We can either choose to extract the digits from left-to-right and assemble from right-to-left, or the opposite. We choose
- the former. The digits are extracted by iteratively dividing by 10, populating the result with the remainders. Haskell
- provides a nice `divMod` function that does both in one fell swoop and returns a tuple `(n, r)` where `r` is the remainder.
- It is a typical example of _anamorphism_, i.e. an unfold. So we'll use `unfoldr` for that.
- ```hs
- digits :: Integer -> [Integer]
- digits = unfoldr step
- where step 0 = Nothing
- step n = let (m, r) = n `divMod` 10 in Just (r, m)
- ```
- Running `digits` on `1234` will indeed give you the list `[4,3,2,1]` in return. Next we turn to `undigits`, which goes in
- the opposition direction. It is an example of a _catamorphism_ aka a fold.
- ```hs
- undigits :: [Integer] -> Integer
- undigits = foldl1' f
- where f m n = 10 * m + n
- ```
- `foldl1` assumes a non-empty list and `foldl1'` is useful when `f` is strict in its argument to avoid blowing up the
- stack. We'll cover this in a future session.
- Running `undigits` on `[4,3,2,1]` will give you back `4321`, which is exactly what we want.
- We move on to `palyndromic`. We can use our `digits` function and prove that a number is palyndromic if its digits are the
- same in both orders:
- ```hs
- palyndromic n = let ns = digits n in ns == reverse ns
- ```
- Finally we turn to `takeWhile`. We could use the version available in the Prelude, but the sequence would **exclude** the
- first number that is palyndromic. So we must come up with our own implementation, which is trivial
- ```hs
- takeWhile :: (a -> Bool) -> [a] -> [a]
- takeWhile p [] = []
- takeWhile p (x:xs) | p x = x : takeWhile p xs
- | otherwise = [x]
- ```
- And we're done ✌️
- ## An alternative definition
- We could take the definition even more literally and `iterate` the RTA algorithm:
- ```hs
- alg196 = takeWhile palyndromic . iterate rta
- ```
- The expression `iterate f x` produces the list `[x, f x, f (f x), f (f (f x)), ...]`, which is quite convenient. We just
- need a proper definition of `rta n` which is simply the number itself added to is own reverse:
- ```hs
- rta n = n + mirror n
- ```
Add Comment
Please, Sign In to add comment