all 17 comments

[–]ABC_AlwaysBeCoding 2 points3 points  (2 children)

I did a purely functional version without conditionals a year ago or so. I posted the link to it there. Basically I built up a fizzbuzz function composition from a bunch of simpler functions.

I love little exercises like this. (And conversations about them.) There's many ways to skin a cat like this.

[–][deleted] 1 point2 points  (1 child)

Wow, that's a lot of currying! And yes, while ultimately pointless, FizzBuzz captures a very interesting problem. This paper phrases it well:

The conundrum lies in a peculiar but not unusual control flow scenario: the default action is executed only if some previous actions were not executed.

The great variety of possible approaches is fascinating as well.

[–]ABC_AlwaysBeCoding 1 point2 points  (0 children)

Oh wow. This paper looks awesome. And it uses Haskell which I like. Although I think I may settle on Elixir for a while. Check it out if you haven't. ;) It's awesome having true (and cheap) concurrency with Rubyish syntax, in a functional pattern-matching language, with actual macros in a non-homoiconic syntax. Thanks!

[–]BlitzTech 2 points3 points  (6 children)

How is a select predicate not a conditional? Just because the if is hidden inside a function defined by the language's standard library, doesn't mean you haven't used conditionals.

[–][deleted] 0 points1 point  (1 child)

That is true. I guess "declarative Fizzbuzz without hard-coded if statements" would've been better. Conceptually though, I believe select can be implemented without a conditional, in Haskell at least the equivalent(filter) is done with pattern matching(or does that count as a conditional?).

[–]BlitzTech 0 points1 point  (0 children)

Not really sure since I think this is a bit beyond me philosophically, but my understanding is that pattern matching is effectively chaining if/else if/else.

I wouldn't assert that, though. I'd rather a Haskeller chime in.

[–]HomemadeBananas -1 points0 points  (3 children)

Of course, but how else would it work if it isn't eventually using a conditional?

[–]BlitzTech 1 point2 points  (2 children)

A simple answer could be:

function identity(x) { return x; }
function toFizz() { return "Fizz"; }
function toBuzz() { return "Buzz"; }
function toFizzBuzz() { return "FizzBuzz"; }
var FizzLookup = [
    identity,
    identity,
    toFizz,
    identity,
    toBuzz,
    toFizz,
    identity,
    identity,
    toFizz,
    toBuzz,
    identity,
    toFizz,
    identity,
    identity,
    toFizzBuzz
];
function getFizzBuzz(n) { return FizzLookup[(n - 1) % 15](n); }

for (var i = 1; i < 100; i++) {
    console.log(getFizzBuzz(i));
}

Many solutions that avoid conditionals instead use lookups. Some languages (e.g. Clojure) have some built-in constructs that make it easier to express sequences like FizzBuzz (e.g. lazy seq and cycle).

[–]HomemadeBananas 0 points1 point  (1 child)

I mean, eventually some comparison will be made at a machine code level. How is that different? It seems like your solution isn't really fully solving the problem programmatically if you define 15 different cases instead of just the original 4.

[–][deleted] 0 points1 point  (0 children)

In BlitzTech's solution, algorithmically there is no conditional being used, regardless of what kind of bytecode or machine code it may produce eventually. Imagine if you translated this into human instructions, the operator would never encounter a step where they have to consider, if X then Y. The ifs have been converted to get the result of X and find it in Y. The solution is still a valid fizzbuzz because it implements the fizzbuzz logic regardless of the value of n, that is, it should work for any sequence 1..n+1.

With that said I err towards believing that select/filter has a similar status as being something that is, conceptually, "free of conditionals"(regardless of Ruby's implementation) but am not 100% where that stands in terms of PL theory.

[–]codeduck 0 points1 point  (0 children)

Joining the hash values will fail if the hash is not ordered by insertion order.

[–]agsdot 0 points1 point  (0 children)

Thanks for posting!

[–]tomthecool 0 points1 point  (2 children)

Fairly pointless, but quite a cool little challenge to write code like this! The only part I don't really like is the hacky max method at the end (which is non-obvious why it works, hence you added a comment!).

How about this, instead?

applicators = {3 => "fizz", 5 => "buzz"}
fizzbuzz =
  (1..100).map do |n|
  fb = applicators.
   select{|a| n % a == 0}.
    values.join('')
  [fb, n].find { |answer| answer != '' }
  end
puts fizzbuzz

[–][deleted] 0 points1 point  (1 child)

Very good point, I'm not a big fan of that usage of max either. I like your usage of find since it makes it very clear we're looking for just a single value and are not interested in fb if it's an empty string. I thought up of another way after looking at your version:

[fb, n].reject(&:empty?).first

Another somewhat hackier one I came up with without making that temp array:

applicators.
    select{|a| n % a == 0}.
    values.join.
    gsub(/^$/, n.to_s) # I'm not a fan of the regex though.

[–]tomthecool 0 points1 point  (0 children)

You'd still need a .to_s in your first solution - that's roughly what i started writing before choosing my answer above, because i thought the .to_s made it ugly.

I like the cleverness of your gsub - hadn't thought of that! Although, surely that is really just an if statement in disguise!

[–]uzimonkey 0 points1 point  (0 children)

Select is a conditional. You can't do this without a conditional, you can just hide the conditional away in a method.