first commit
This commit is contained in:
commit
99a1aa94c5
BIN
.fizzbuzz.rkt.swp
Normal file
BIN
.fizzbuzz.rkt.swp
Normal file
Binary file not shown.
203
README.md
Normal file
203
README.md
Normal file
@ -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
|
49
fizzbuzz.rkt
Normal file
49
fizzbuzz.rkt
Normal file
@ -0,0 +1,49 @@
|
|||||||
|
#lang racket
|
||||||
|
|
||||||
|
(define (skip s)
|
||||||
|
s)
|
||||||
|
|
||||||
|
(define (halt s)
|
||||||
|
"")
|
||||||
|
|
||||||
|
(define (myprint s x)
|
||||||
|
(string-append s x))
|
||||||
|
|
||||||
|
(define (base n)
|
||||||
|
(lambda (k)
|
||||||
|
(lambda (s)
|
||||||
|
(k (myprint (number->string n) s)))))
|
||||||
|
|
||||||
|
(define (mult n)
|
||||||
|
(lambda (k) (= 0 (modulo k n))))
|
||||||
|
|
||||||
|
(require (for-syntax syntax/parse racket/base))
|
||||||
|
|
||||||
|
(begin-for-syntax
|
||||||
|
(define-syntax-class fbline
|
||||||
|
#:description "predicate string pair"
|
||||||
|
(pattern (p:expr m:string))))
|
||||||
|
|
||||||
|
(define-syntax (create-trigger stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(_ p:expr m:string)
|
||||||
|
#'(lambda (n)
|
||||||
|
(lambda (k)
|
||||||
|
(lambda (s)
|
||||||
|
(if (p n)
|
||||||
|
(myprint m (k (halt s)))
|
||||||
|
(k s)))))]))
|
||||||
|
|
||||||
|
(define-syntax (define-fizzbuzz stx)
|
||||||
|
(syntax-parse stx
|
||||||
|
[(_ name:identifier l:fbline ...)
|
||||||
|
#'(define (name n)
|
||||||
|
(((compose (base n)
|
||||||
|
((create-trigger l.p l.m) n) ...)
|
||||||
|
skip) ""))]))
|
||||||
|
|
||||||
|
(define-fizzbuzz fizzbuzz
|
||||||
|
[(mult 3) "Fizz"]
|
||||||
|
[(mult 5) "Buzz"])
|
||||||
|
|
||||||
|
(provide mult define-fizzbuzz fizzbuzz)
|
Loading…
Reference in New Issue
Block a user