3 ms·
Another language that supports (arbitrary) compile time code execution is Haskell through Template Haskell. Ex. using FizzBuzz: -- FizzBuzz.hs module Fi
by valcron1000 4y ago
Another language that supports (arbitrary) compile time code execution is Haskell through Template Haskell. Ex. using FizzBuzz:
-- FizzBuzz.hs
module FizzBuzz (fizzBuzz) where
fizzBuzz :: Int -> String
fizzBuzz n
| n `mod` 15 == 0 = "FizzBuzz"
| n `mod` 3 == 0 = "Fizz"
| n `mod` 5 == 0 = "Buzz"
| otherwise = show n
-- Main.hs
import FizzBuzz (fizzBuzz)
import Language.Haskell.TH.Syntax (lift)
main :: IO ()
main = do
print $(lift $ map fizzBuzz [1 .. 100])
As you can see, the fizzbuzz function does not need any special syntax or annotations. You can use any code at compile time. The only downside is that you need to separate the code into two modules.
Other solutions involve using the type system to do this kind of computation at compile time, but I think that TH is very powerful (maybe too powerful since you can run arbitrary IO at compile time).
- emidln 4y agoTo 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.