13brane's holidazed cavalcade of code shenanigans: the flavors of FizzBuzz - Days 9-16

 

(Full source code for the entire series will be progressively published here, and the other days of the cavalcade are here: day 0, 1-8, 17-24)

FizzBuzz is a problem that maps rather well into functional programming (at least as long as you don’t try to overcomplicate things), so it is completely appropriate that we forego all state manipulations and refuse to do anything with variables that could not be mapped directly to a let ... in ... construct.

In other words: what would happen if you got a bunch of Haskell academics and force fed them Go with a large spoon?

Answer: Much wailing and gnashing of teeth.

Day 9

CompSci 232, Programming Paradigms. Data transformations only. Student is a bit puzzled about the hype around FP, but managed to come up with something which works and is not extra contrived.

package day09

import "fmt"

type IntString struct {
	i int
	s string
}

func FizzBuzz(i int) string {
	return stringOf(buzzOf(fizzOf(IntString{i, ""})))
}

func fizzOf(a IntString) IntString {
	if a.i%3 == 0 {
		return IntString{a.i, a.s + "fizz"}
	} else {
		return a
	}
}

func buzzOf(a IntString) IntString {
	if a.i%5 == 0 {
		return IntString{a.i, a.s + "buzz"}
	} else {
		return a
	}
}

func stringOf(a IntString) string {
	if len(a.s) == 0 {
		return fmt.Sprint(a.i)
	} else {
		return a.s
	}
}

Note: any similarities with Day 2 are purely coincidental.

Day 10

Finalist undergrad student. Already has a thing for Haskell. Clearly wants to pursue an academic career (the poor soul). Actually solved the problem in Haskell first, then transpiled the code by hand with minor modifications.

package day10

import "fmt"

// tuple, (int, string)
type IntString struct {
	i int
	s string
}

// FizzBuzz :: int -> string
func FizzBuzz(i int) string {
	return stringOf(buzzOf(fizzOf(IntString{i, ""})))
}

// fizzOf :: (int, string) -> (int, string)
func fizzOf(x IntString) IntString {
	return xof(divisibleBy(3), "fizz")(x)
}

// buzzOf :: (int, string) -> (int, string)
func buzzOf(x IntString) IntString {
	return xof(divisibleBy(5), "buzz")(x)
}

// xof :: (int -> bool) -> string -> ((int, string) -> (int, string))
func xof(check func(int) bool, rule string) func(IntString) IntString {
	return func(a IntString) IntString {
		if check(a.i) {
			return IntString{a.i, a.s + rule}
		} else {
			return a
		}
	}
}

// stringOf :: (int, string) -> string
func stringOf(a IntString) string {
	if len(a.s) == 0 {
		return fmt.Sprint(a.i)
	} else {
		return a.s
	}
}

// divisibleBy :: int -> (int -> bool)
func divisibleBy(n int) func(int) bool {
	return func(i int) bool {
		return i%n == 0
	}
}

Day 11

Master’s student. Totally at ease with FP. Desperately wants to curry. Is starting to question life choices.

package day11

import "fmt"

// Why aren't we doing this in Haskell, again?

// (int, string) tuple
type IntString struct {
	i int
	s string
}

// simulate deriving Show for IntString
func (x IntString) String() string {
	if len(x.s) == 0 {
		return fmt.Sprint(x.i)
	} else {
		return x.s
	}
}

// FizzBuzz :: int -> string
func FizzBuzz(n int) string {

	// looks rather stupid without `let`

	// divisibleBy :: int -> (int -> bool)
	divisibleBy := func(n int) func(int) bool {
		return func(i int) bool {
			return i%n == 0
		}
	}

	// xof :: (int -> bool) -> string -> ((int, string) -> (int, string))
	xof := func(check func(int) bool, rule string) func(IntString) IntString {
		return func(x IntString) IntString {
			if check(x.i) {
				return IntString{x.i, x.s + rule}
			} else {
				return x
			}
		}
	}

	// currying? Would if I could.

	// fizzOf :: (int, string) -> (int, string)
	fizzOf := xof(divisibleBy(3), "fizz")

	// buzzOf :: (int, string) -> (int, string)
	buzzOf := xof(divisibleBy(5), "buzz")

	return buzzOf(fizzOf(IntString{n, ""})).String()
}

Day 12

PhD student. Wants to bring in the big Algebraic Data Type guns, and shoots himself in the foot doing so. Is really questioning some life choices. Can’t even find time to curry, much less anyone to do it with.

package day12

import "fmt"

// This is just silly. We could have used Rust.

// Let's pretend we have monads, destructuring, pattern matching
// and data constructors.

// data FB = AFizz a | ABuzz a | AFizzBuzz a | APlain a
type FB interface {
	Plain() int
	String() string
}

type APlain struct {
	p int
}

func (p APlain) Plain() int {
	return p.p
}
func (p APlain) String() string {
	return fmt.Sprint(p.p)
}

type AFizz struct {
	APlain
}

func (f AFizz) String() string {
	return "fizz"
}

type ABuzz struct {
	APlain
}

func (b ABuzz) String() string {
	return "buzz"
}

type AFizzBuzz struct {
	APlain
}

func (f AFizzBuzz) String() string {
	return "fizzbuzz"
}

func FizzBuzz(i int) string {
	return buzz(fizz(APlain{i})).String()
}

// really, I'm going to ask my advisor why he's an idiot.

func fizz(x FB) FB {
	mod3 := x.Plain()%3 == 0

	if mod3 {
		switch x.(type) {
		case APlain:
			return AFizz{APlain{x.Plain()}}
		case ABuzz:
			return AFizzBuzz{APlain{x.Plain()}}
		default:
			return x
		}
	} else {
		return x
	}
}

func buzz(x FB) FB {
	mod5 := x.Plain()%5 == 0

	if mod5 {
		switch x.(type) {
		case APlain:
			return ABuzz{APlain{x.Plain()}}
		case AFizz:
			return AFizzBuzz{APlain{x.Plain()}}
		default:
			return x
		}
	} else {
		return x
	}
}

// oh god, kill me now.

Day 13

PhD advisor. The kind that berates students for not knowing subjects he is paid to teach. Fervent believer of the “hair-shirt approach”. Is considering asking next year’s students to implement a purely functional virtual machine. Someone should tell him about this. And remind him that decrement is not a good primitive in terms of CPU cycle usage.

package day13

import "fmt"

// my master's and phd students are dense. It's just one of those batches. If
// they got off imgur I'm sure their output would improve, but cat pictures
// are a good use of student loans in 2018... The point of the exercise was
// to understand exactly how much effort is required to translate functional
// features to a non functional language. Translating Haskell to Haskell is
// not a good use of grants. Nimrods.

type (
	// data FB = Fizz FB | Buzz FB | Just a
	FB interface {
		Value() int
	}

	Just struct {
		i int
	}

	Buzz struct {
		fb FB
	}

	Fizz struct {
		fb FB
	}
)

// make constructors part of data class
func (j Just) Value() int { return j.i }
func (b Buzz) Value() int { return b.fb.Value() }
func (f Fizz) Value() int { return f.fb.Value() }

// buzz :: int -> FB
func buzz(n int) FB {
	if n%5 == 0 {
		return Buzz{Just{n}}
	} else {
		return Just{n}
	}
}

// fizz :: FB -> FB
func fizz(fb FB) FB {
	if fb.Value()%3 == 0 {
		return Fizz{fb}
	} else {
		return fb
	}
}

// show :: FB -> string -> string
func show(fb FB, prev string) string {
	switch v := fb.(type) {
	case Just:
		if len(prev) != 0 {
			return prev
		} else {
			return fmt.Sprint(v.i)
		}
	case Fizz:
		return show(v.fb, prev+"fizz")
	case Buzz:
		return show(v.fb, prev+"buzz")
	default:
		return "" // never happens, only makes compiler happy
	}
}

func FizzBuzz(n int) string {
	return show(fizz(buzz(n)), "")
}

Day 14

Tenured professor. The kind that berates other professors for berating students.

package day14

import "fmt"

// Note to Dr. Ethelbert:
// I am not sure the students are the problem.

func FizzBuzz(n int) string {
	return IfThenElse(
		Cond(n%3 == 0),
		IfThenElse(
			Cond(n%5 == 0),
			Value("fizzbuzz"),
			Value("fizz"),
		),
		IfThenElse(
			Cond(n%5 == 0),
			Value("buzz"),
			ToString(n),
		),
	).Solve()
}

// Haskell is for wimps. For a true hair-shirt experience, you should
// implement a (crude) lambda calculus interpreter instead.
type Calc struct {
	f func() string
}

func (c Calc) Solve() string {
	return c.f()
}

func True(x, _ Calc) Calc {
	return x
}

func False(_, y Calc) Calc {
	return y
}

func IfThenElse(c func(Calc, Calc) Calc, t, f Calc) Calc {
	return c(t, f)
}

// Go->Lambda and Lambda->Go transformations

func Cond(b bool) func(Calc, Calc) Calc {
	return map[bool]func(Calc, Calc) Calc{true: True, false: False}[b]
}

func Value(s string) Calc {
	return Calc{func() string {
		return s
	}}
}

func ToString(n int) Calc {
	return Calc{func() string {
		return fmt.Sprint(n)
	}}
}

// Oh, and we need to talk about grant allocations...

Day 15

Self taught l33t h4x0r. Is into cryptography and applied math. Noticed that the outputs of FizzBuzz(n) are cyclical with a period of 15 over the input integers, and proceeded to abuse Go arrays on that basis.

Also wants to remind us not to use (3,5) as the semiprimes for an RSA private key.

Got it.

Fun fact: at the time of this writing, there were at least 36 RSA Moduli all over the web with 3 as a prime factor. No need for anti-encryption laws, people.

package day15

import "fmt"

func FizzBuzz(n int) string {
	x := [15]string{
		"fizzbuzz", "", "", "fizz", "",
		"buzz", "fizz", "", "", "fizz",
		"buzz", "", "fizz", "", "",
	}[n%15]

	if x == "" {
		return fmt.Sprint(n)
	} else {
		return x
	}
}

Day 16

Another, more experient, uber-l33t h4x0r. Is into all sorts of things, including your home router. Thinks flow control is for sissies and prefers to abuse first class functions and arrays in order to avoid writing one if statement. Likes to code-golf in APL, swap variables without a tempvar and mine various cryptocurrencies via JS snippets distributed through your niche WordPress blog.

package day16

import "fmt"

func fb(_ int) string { return "fizzbuzz" }
func f(_ int) string  { return "fizz" }
func b(_ int) string  { return "buzz" }
func s(n int) string  { return fmt.Sprint(n) }

func FizzBuzz(n int) string {
	return [15]func(int) string{
		fb, s, s, f, s,
		b, f, s, s, f,
		b, s, f, s, s,
	}[n%15](n)
}

Tune in next week for the ultimate sacrilege: Object Oriented FizzBuzzes, and a couple of extras.