
Nearly a decade ago, I wrote a post about implementing FizzBuzz in a more functional manner, which also happened to be the final entry on a blog I started that year. Now, I want to dedicate more time to writing, and rebooting my blog seems to be a good way to achieve this. What better way to begin than by revisiting my previous post and picking up where I left off?
I believe the article is still fine, but reading it feels like looking at old code I wrote: slightly awkward. Now, I would change some parts which I may do in upcoming posts but let's start simple and rewrite in Scala 3. This is the code I left with last time:
def fizzbuzz(s: Int): List[String] = {
// helper method inspired by haskell, cycle a list infinitely,
def cycle(xs: List[String]): Stream[String] = Stream.continually(xs).flatten
// a infinite cycle of "", "", "Fizz"
val fizzes = cycle(List("", "", "Fizz"))
// a infinite cycle of "", "", "", "", "Buzz"
val buzzes = cycle(List("", "", "", "", "Buzz"))
// zip the fizzes and buzzes, and concatenate them, result is "", "", "Fizz", "", "Buzz", "Fizz", ...
val pattern = fizzes zip buzzes map { case (f, b) => f + b }
// zip numbers with the pattern, if the pattern is empty keep the number, otherwise keep the pattern
val numbers = Stream.from(1)
val numbersAndPattern = numbers zip pattern map {
case (n, p) => if (p.isEmpty) n.toString else p
}
numbersAndPattern take s toList
}
Below is a Scala 3 version in which I comment on the changes. Note that I added a Scala 3 version of a `main` function which can be run using Scala CLI.
// Commenting the Scala 3 version / Scala CLI directive
//> using scala 3.3.1
// optional significant white spacing, we can omit all curly braces
@main def fizzbuzz(): Unit =
def fizzbuzz(s: Int): List[String] =
// `Stream` is replaced with `LazyList`, the latter being fully lazy.
def cycle(xs: List[String]): LazyList[String] = LazyList.continually(xs).flatten
val fizzes = cycle(List("", "", "Fizz"))
val buzzes = cycle(List("", "", "", "", "Buzz"))
// case matches on tuples are not required anymore
val pattern = fizzes zip buzzes map(_ + _)
val numbers = LazyList.from(1)
// again case match on tuples removed
val numbersAndPattern = numbers zip pattern map:
(n, p) =>
// if-then-else statement
if p.isEmpty then n.toString else p
// here extra braces are required
(numbersAndPattern take s).toList
// not required, explicit end clause for larger functions
end fizzbuzz
fizzbuzz(20).foreach(fb => print(fb + "," ))
This will print 1,2,Fizz,4,Buzz,Fizz,7,8,Fizz,Buzz,11,Fizz,13,14,FizzBuzz,16,17,Fizz,19,Buzz,.
Most notable is the significant white spacing. I understand it is not to everybody's taste but I quite like it. I admit sometimes I get unexpected compiler errors because of it but nothing big not frequently. Another nice improvement which always was weird is that now the `case` matches on tuples can be removed when mapping.
Cleaning up a little a removing superfluous comments I leave it at:
// Commenting the Scala 3 version / Scala CLI directive
//> using scala 3.3.1
@main def fizzbuzz(): Unit =
def fizzbuzz(s: Int): List[String] =
def cycle(xs: List[String]): LazyList[String] = LazyList.continually(xs).flatten
val fizzes = cycle(List("", "", "Fizz"))
val buzzes = cycle(List("", "", "", "", "Buzz"))
val pattern = fizzes zip buzzes map (_ + _)
val numbers = LazyList.from(1)
val numbersAndPattern = numbers zip pattern map: (n, p) =>
if p.isEmpty then n.toString else p
(numbersAndPattern take s).toList
end fizzbuzz
fizzbuzz(20).foreach(fb => print(fb + ","))
end fizzbuzz
About the author
I write about: Software architecture and engineering, Better software better. DDD, Scala and Rust
Comments
Join the discussionNo comments yet. Be the first to comment.
FizzBuzz Fun in Scala
Some fun and exploring of FizzBuzz implementations in functional programming style and Scala 3.