Guest User

Untitled

a guest
Jun 23rd, 2018
91
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 3.71 KB | None | 0 0
  1. Let's see what Wolfram Alpha has for us:
  2.  
  3. > RTA is the sequence obtained from reversing the digits of a number _n_ and adding the result to the original number.
  4. > The 196-algorithm operates RTA iteratively until a palyndromic number is obtained.
  5.  
  6. Let's define alg196 then. We can take the definition above literally and get the following script:
  7. ```hs
  8. alg196 :: Integer -> [Integer]
  9. alg196 n = takeWhile palyndromic . rtaseq n
  10. ```
  11.  
  12. `rtaseq` will produce an infinite stream of numbers, but we only care about those up to the first that is palyndromic.
  13. Essentially we want to produce the sequence
  14. ```hs
  15. rtaseq n = n : n2 : n3 : n4 : ...
  16. where n2 = n + reverse n
  17. n3 = n2 + reverse n2
  18. n4 = n3 + reverse n3
  19. ...
  20. ```
  21.  
  22. We notice that each element of the list depends on the previous one. There are many ways to express that in Haskell, but
  23. 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
  24. list that starts with `1` followed by the list itself where every element is added to 1.
  25. ```hs
  26. plus1 = 1 : fmap (+1) plus1
  27. ```
  28.  
  29. 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
  30. pair-wise the elements of the list itself with the elements of the list "mirrored", i.e. where the digits have been reversed:
  31. ```hs
  32. rtaseq n = ns where ns = n : zipWith (+) ns (fmap mirror ns)
  33. ```
  34.  
  35. The `mirror` function can be described in a two-step process: first get the digits, then reassemble them in reverse order.
  36. ```hs
  37. mirror :: Integer -> Integer
  38. mirror = undigits . digits
  39. ```
  40.  
  41. We can either choose to extract the digits from left-to-right and assemble from right-to-left, or the opposite. We choose
  42. the former. The digits are extracted by iteratively dividing by 10, populating the result with the remainders. Haskell
  43. provides a nice `divMod` function that does both in one fell swoop and returns a tuple `(n, r)` where `r` is the remainder.
  44.  
  45. It is a typical example of _anamorphism_, i.e. an unfold. So we'll use `unfoldr` for that.
  46. ```hs
  47. digits :: Integer -> [Integer]
  48. digits = unfoldr step
  49. where step 0 = Nothing
  50. step n = let (m, r) = n `divMod` 10 in Just (r, m)
  51. ```
  52.  
  53. Running `digits` on `1234` will indeed give you the list `[4,3,2,1]` in return. Next we turn to `undigits`, which goes in
  54. the opposition direction. It is an example of a _catamorphism_ aka a fold.
  55. ```hs
  56. undigits :: [Integer] -> Integer
  57. undigits = foldl1' f
  58. where f m n = 10 * m + n
  59. ```
  60.  
  61. `foldl1` assumes a non-empty list and `foldl1'` is useful when `f` is strict in its argument to avoid blowing up the
  62. stack. We'll cover this in a future session.
  63.  
  64. Running `undigits` on `[4,3,2,1]` will give you back `4321`, which is exactly what we want.
  65.  
  66. We move on to `palyndromic`. We can use our `digits` function and prove that a number is palyndromic if its digits are the
  67. same in both orders:
  68. ```hs
  69. palyndromic n = let ns = digits n in ns == reverse ns
  70. ```
  71.  
  72. Finally we turn to `takeWhile`. We could use the version available in the Prelude, but the sequence would **exclude** the
  73. first number that is palyndromic. So we must come up with our own implementation, which is trivial
  74. ```hs
  75. takeWhile :: (a -> Bool) -> [a] -> [a]
  76. takeWhile p [] = []
  77. takeWhile p (x:xs) | p x = x : takeWhile p xs
  78. | otherwise = [x]
  79. ```
  80.  
  81. And we're done ✌️
  82.  
  83. ## An alternative definition
  84.  
  85. We could take the definition even more literally and `iterate` the RTA algorithm:
  86. ```hs
  87. alg196 = takeWhile palyndromic . iterate rta
  88. ```
  89.  
  90. The expression `iterate f x` produces the list `[x, f x, f (f x), f (f (f x)), ...]`, which is quite convenient. We just
  91. need a proper definition of `rta n` which is simply the number itself added to is own reverse:
  92. ```hs
  93. rta n = n + mirror n
  94. ```
Add Comment
Please, Sign In to add comment