|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203 |
- # 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
|