4 ms·
To take on another language solution, here's an obvious one, albeit in a lisp (Clojure): (defn fizzbuzz-nth* [n] (cond (zero? (mod n 15)) "Fi
by emidln 4y ago
To take on another language solution, here's an obvious one, albeit in a lisp (Clojure):
(defn fizzbuzz-nth* [n]
(cond
(zero? (mod n 15)) "FizzBuzz"
(zero? (mod n 3)) "Fizz"
(zero? (mod n 5)) "Buzz"
:else (str n)))
(defn fizzbuzz* [n]
(->> (range 1 (inc n))
(map fizzbuzz-nth*)
(interpose " ")
(apply str)))
(defmacro fizzbuzz [n]
`(println ~(fizzbuzz* n)))
(println "macroexpansion: ")
(println (macroexpand '(fizzbuzz 100)))
(println)
(println "invoke the macro: ")
(fizzbuzz 100)
Compile-time programming isn't any different than runtime programming in a lisp. This is nice because we can write the business parts as regular code, which is easy to try out in the repl or write tests for and then wrap it in a macro for compile-time evaluation if that's what the situation calls for.
For those not versed in lisp, `fizzbuzz-nth` and `fizzbuzz` are regular functions and `fizzbuzz` is a macro (aka a function annotated to be executed at compile time). The `fizzbuzz` macro makes use of Clojure's `syntax-quote` (the backtick) to signify templating is going on and `unquote` (the tilde) to escape the templating and execute some code at macro expansion time.
It's a real shame most languages don't have these metaprogramming facilities as judicious use makes weird, hard, and untestable stuff into common, easy, and another boring part of the test suite.
I'm really pulling for C++ to eventually get here with templates, particularly now that vectors can be constexpr and the result of templates. Maybe c++26 will finally give us reasonable macro facilities in a mainstream language.