FizzBuzz Macro
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

README.md 4.4KB

3 years ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203
  1. # FizzBuzz Macro
  2. a small macro for defining FizzBuzz-like functions easily.
  3. uses continuation passing to ensure each predicate is only checked once per number.
  4. ## usage
  5. import the file into your `#lang racket` project
  6. ```
  7. (require "fizzbuzz.rkt")
  8. ```
  9. from there the functions `mult`, `fizzbuzz` and `define-fizzbuzz` will be avaliable to you.
  10. ### mult
  11. `(mult x)` creates a predicate that answers whether a number is a multiple of `x`
  12. ```
  13. ((mult 5) 15) => #t
  14. ((mult 5) 16) => #f
  15. ```
  16. ### fizzbuzz
  17. `(fizzbuzz x)` is an implementation of fizzbuzz using this program. it returns a string which will be one of:
  18. * the string representation of `x`
  19. * the string "Fizz"
  20. * the string "Buzz"
  21. * the string "FizzBuzz"
  22. it is defined using `define-fizzbuzz` and `mult` as follows:
  23. ```
  24. (define-fizzbuzz fizzbuzz
  25. [(mult 3) "Fizz"]
  26. [(mult 5) "Buzz"])
  27. ```
  28. ### define-fizzbuzz
  29. `define-fizzbuzz` takes a name, and a list of predicate, string pairs, and creates a function that acts as fizzbuzz would for any number of triggers.
  30. the order of the pairs will determine the ordering of the strings should more than one be true for a given number, ie. the difference between "FizzBuzz" and "BuzzFizz" is the ordering of the pairs.
  31. ## example
  32. in order to define the function `bashforkfoobar` which has the following semantics:
  33. * if `x` is odd, "Bash"
  34. * if `x` is a multiple of 7, "Fork"
  35. * if `x - 2` is a multiple of 3, "Foo"
  36. * if `x` is 69, "Bar"
  37. we can use the following;
  38. ```
  39. (define-fizzbuzz bashforkfoobar
  40. [odd? "Bash"]
  41. [(mult 7) "Fork"]
  42. [(lambda (n) ((mult 3) (- n 2))) "Foo"]
  43. [(lambda (n) (= n 69) "Bar"])
  44. ```
  45. which when mapped over a range of numbers using `(map bashforfoobar (range 1 101)`;
  46. ```
  47. '("Bash"
  48. "Foo"
  49. "Bash"
  50. "4"
  51. "BashFoo"
  52. "6"
  53. "BashFork"
  54. "Foo"
  55. "Bash"
  56. "10"
  57. "BashFoo"
  58. "12"
  59. "Bash"
  60. "ForkFoo"
  61. "Bash"
  62. "16"
  63. "BashFoo"
  64. "18"
  65. "Bash"
  66. "Foo"
  67. "BashFork"
  68. "22"
  69. "BashFoo"
  70. "24"
  71. "Bash"
  72. "Foo"
  73. "Bash"
  74. "Fork"
  75. "BashFoo"
  76. "30"
  77. "Bash"
  78. "Foo"
  79. "Bash"
  80. "34"
  81. "BashForkFoo"
  82. "36"
  83. "Bash"
  84. "Foo"
  85. "Bash"
  86. "40"
  87. "BashFoo"
  88. "Fork"
  89. "Bash"
  90. "Foo"
  91. "Bash"
  92. "46"
  93. "BashFoo"
  94. "48"
  95. "BashFork"
  96. "Foo"
  97. "Bash"
  98. "52"
  99. "BashFoo"
  100. "54"
  101. "Bash"
  102. "ForkFoo"
  103. "Bash"
  104. "58"
  105. "BashFoo"
  106. "60"
  107. "Bash"
  108. "Foo"
  109. "BashFork"
  110. "64"
  111. "BashFoo"
  112. "66"
  113. "Bash"
  114. "Foo"
  115. "BashBar"
  116. "Fork"
  117. "BashFoo"
  118. "72"
  119. "Bash"
  120. "Foo"
  121. "Bash"
  122. "76"
  123. "BashForkFoo"
  124. "78"
  125. "Bash"
  126. "Foo"
  127. "Bash"
  128. "82"
  129. "BashFoo"
  130. "Fork"
  131. "Bash"
  132. "Foo"
  133. "Bash"
  134. "88"
  135. "BashFoo"
  136. "90"
  137. "BashFork"
  138. "Foo"
  139. "Bash"
  140. "94"
  141. "BashFoo"
  142. "96"
  143. "Bash"
  144. "ForkFoo"
  145. "Bash"
  146. "100")
  147. ```
  148. ## explanation
  149. the macro creates a composition of continuation style passing functions, which will build a string and halt production in order to prevent a number being printed if an identifier has been.
  150. the string building functions `myprint`, `skip` and `halt` are quite simple.
  151. `skip` and `halt` both take a string and return a string, with `skip` acting as the identity function, and `halt` intead throwing away its argument and returning the empty string (the unit value for this composition).
  152. `myprint` takes two strings and returns a string. the first is the message to add to the end of the string being built, and the second (curried) argument works as in `skip` and `halt`.
  153. `base` exists as a CPS function that creates (once passed a continuation) a function from string to string, simply applying its continuation to the result of printing the number passed to `base`. it is the first rule in any fizzbuzz function to facilitate the default behaviour.
  154. the macro then constructs an additional trigger for each predicate / string pair, which when given a number, returns a CPS function that when given a continuation will take a string, and either pass it unchanged to the continuation, or sandwich the continuation between a `myprint` and a `halt`, such that the halt will prevent the default behaviour.
  155. after macro transformations, a trigger with the message `message` and the predicate `predicate` will look as follows:
  156. ```
  157. (lambda (n)
  158. (lambda (k)
  159. (lambda (s)
  160. (if (p n)
  161. (myprint m (k (halt s)))
  162. (k s)))))
  163. ```
  164. here, `n` is the number passed to the fizzbuzz function, `k` is the continuation function, and `s` is the string for the final string builder.
  165. these are composed starting with `base`, and then each trigger in order to create the final fizzbuzz function.
  166. ## author
  167. * tA