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