|
|
@@ -0,0 +1,203 @@ |
|
|
|
# FizzBuzz Macro |
|
|
|
|
|
|
|
a small macro for defining FizzBuzz-like functions easily. |
|
|
|
uses continuation passing to ensure each predicate is only checked once per number. |
|
|
|
|
|
|
|
## usage |
|
|
|
|
|
|
|
import the file into your `#lang racket` project |
|
|
|
|
|
|
|
``` |
|
|
|
(require "fizzbuzz.rkt") |
|
|
|
``` |
|
|
|
|
|
|
|
from there the functions `mult`, `fizzbuzz` and `define-fizzbuzz` will be avaliable to you. |
|
|
|
|
|
|
|
### mult |
|
|
|
|
|
|
|
`(mult x)` creates a predicate that answers whether a number is a multiple of `x` |
|
|
|
|
|
|
|
``` |
|
|
|
((mult 5) 15) => #t |
|
|
|
((mult 5) 16) => #f |
|
|
|
``` |
|
|
|
|
|
|
|
### fizzbuzz |
|
|
|
|
|
|
|
`(fizzbuzz x)` is an implementation of fizzbuzz using this program. it returns a string which will be one of: |
|
|
|
|
|
|
|
* the string representation of `x` |
|
|
|
* the string "Fizz" |
|
|
|
* the string "Buzz" |
|
|
|
* the string "FizzBuzz" |
|
|
|
|
|
|
|
it is defined using `define-fizzbuzz` and `mult` as follows: |
|
|
|
|
|
|
|
``` |
|
|
|
(define-fizzbuzz fizzbuzz |
|
|
|
[(mult 3) "Fizz"] |
|
|
|
[(mult 5) "Buzz"]) |
|
|
|
``` |
|
|
|
|
|
|
|
### define-fizzbuzz |
|
|
|
|
|
|
|
`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. |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
## example |
|
|
|
|
|
|
|
in order to define the function `bashforkfoobar` which has the following semantics: |
|
|
|
|
|
|
|
* if `x` is odd, "Bash" |
|
|
|
* if `x` is a multiple of 7, "Fork" |
|
|
|
* if `x - 2` is a multiple of 3, "Foo" |
|
|
|
* if `x` is 69, "Bar" |
|
|
|
|
|
|
|
we can use the following; |
|
|
|
|
|
|
|
``` |
|
|
|
(define-fizzbuzz bashforkfoobar |
|
|
|
[odd? "Bash"] |
|
|
|
[(mult 7) "Fork"] |
|
|
|
[(lambda (n) ((mult 3) (- n 2))) "Foo"] |
|
|
|
[(lambda (n) (= n 69) "Bar"]) |
|
|
|
``` |
|
|
|
|
|
|
|
which when mapped over a range of numbers using `(map bashforfoobar (range 1 101)`; |
|
|
|
|
|
|
|
``` |
|
|
|
'("Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"4" |
|
|
|
"BashFoo" |
|
|
|
"6" |
|
|
|
"BashFork" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"10" |
|
|
|
"BashFoo" |
|
|
|
"12" |
|
|
|
"Bash" |
|
|
|
"ForkFoo" |
|
|
|
"Bash" |
|
|
|
"16" |
|
|
|
"BashFoo" |
|
|
|
"18" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"BashFork" |
|
|
|
"22" |
|
|
|
"BashFoo" |
|
|
|
"24" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"Fork" |
|
|
|
"BashFoo" |
|
|
|
"30" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"34" |
|
|
|
"BashForkFoo" |
|
|
|
"36" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"40" |
|
|
|
"BashFoo" |
|
|
|
"Fork" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"46" |
|
|
|
"BashFoo" |
|
|
|
"48" |
|
|
|
"BashFork" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"52" |
|
|
|
"BashFoo" |
|
|
|
"54" |
|
|
|
"Bash" |
|
|
|
"ForkFoo" |
|
|
|
"Bash" |
|
|
|
"58" |
|
|
|
"BashFoo" |
|
|
|
"60" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"BashFork" |
|
|
|
"64" |
|
|
|
"BashFoo" |
|
|
|
"66" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"BashBar" |
|
|
|
"Fork" |
|
|
|
"BashFoo" |
|
|
|
"72" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"76" |
|
|
|
"BashForkFoo" |
|
|
|
"78" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"82" |
|
|
|
"BashFoo" |
|
|
|
"Fork" |
|
|
|
"Bash" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"88" |
|
|
|
"BashFoo" |
|
|
|
"90" |
|
|
|
"BashFork" |
|
|
|
"Foo" |
|
|
|
"Bash" |
|
|
|
"94" |
|
|
|
"BashFoo" |
|
|
|
"96" |
|
|
|
"Bash" |
|
|
|
"ForkFoo" |
|
|
|
"Bash" |
|
|
|
"100") |
|
|
|
``` |
|
|
|
|
|
|
|
## explanation |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
the string building functions `myprint`, `skip` and `halt` are quite simple. |
|
|
|
|
|
|
|
`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). |
|
|
|
|
|
|
|
`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`. |
|
|
|
|
|
|
|
`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. |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
after macro transformations, a trigger with the message `message` and the predicate `predicate` will look as follows: |
|
|
|
|
|
|
|
``` |
|
|
|
(lambda (n) |
|
|
|
(lambda (k) |
|
|
|
(lambda (s) |
|
|
|
(if (p n) |
|
|
|
(myprint m (k (halt s))) |
|
|
|
(k s))))) |
|
|
|
``` |
|
|
|
|
|
|
|
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. |
|
|
|
|
|
|
|
these are composed starting with `base`, and then each trigger in order to create the final fizzbuzz function. |
|
|
|
|
|
|
|
## author |
|
|
|
|
|
|
|
* tA |