But I think that the point of functional programming is to provide a layer of programming that exposes a clean API. You know: now side effects, no global variables etc..
People don't always write Python in a functional style, but I imagine that the itertools module was created out of admiration (or jealousy) for other languages that can do some of these things. :-)
Here's a different sort-of-functional python fizzbuzz.
While it doesn't use the spiffy lazy lists of
itertools, and does have the typical
"if x % n == 0" test, it does generalize easily
to the "and print Baz every 37th number" case.
def joinmap(func, elements, separator):
return separator.join(map(func, elements))
def fb_value(x, fb={3:'Fizz', 5:'Buzz'}):
words = joinmap(lambda n: fb[n] if x % n == 0 else '', fb.keys(), '')
return words if words else str(x)
def fb_range(low=1, high=100):
return joinmap(fb_value, range(low, 1 + high), '\n')
print fb_range()
A problem that this highlights is that the order in which the Fizz and Buzz and other strings get concatenated depends on the order of the underlying dictionary hash, which can be thought of as random. In Python 3 it even changes from run to run.
Probably a valid complaint against code like this. In an organization with a lot of more junior developers I might strike this code in a code review as being non obvious. On the other hand, I trust this code more than similar basic conditional based fizzbuzz since there's no conditionals or nested logic to get wrong. It's also simple to extend, ie, a 'Bazz' on 7 requirement would be adding one more cycle to the mix.
I was being intentionally verbose so that readers not familiar with Scala or the collections types/methods used would have an easier time following it. I also was avoiding use of pattern matching as they are cousins to conditionals IMHO.
However, below is another version which employs idioms more commonly found:
object Fizzbuzz
{
val fizzes = None :: None :: Some ("Fizz") :: Nil;
val buzzes = None :: None :: None :: None :: Some ("Buzz") :: Nil;
def apply (amount : Int) : TraversableOnce[String] =
{
val alternates = Stream.continually (fizzes).flatten
.zip (Stream.continually (buzzes).flatten)
.take (amount)
.toArray;
0.until (amount).map { n =>
alternates (n) match {
case (Some (f), Some (b)) => f + b;
case (Some (f), None) => f;
case (None, Some (b)) => b;
case _ => (n + 1).toString
}
}
}
}
Fizzbuzz (100).foreach (println);
Gotcha. Then here's a translation into Scala from the link you provided which I believe maintains the spirit of the clojure version:
object Fizzbuzz
{
def apply (amount : Int) : TraversableOnce[String] =
1.to (amount).map { n =>
(n % 3, n % 5) match {
case (0, 0) => "FizzBuzz";
case (0, _) => "Fizz";
case (_, 0) => "Buzz";
case _ => n.toString
}
}
}
Fizzbuzz (100).foreach (println);
EDIT: When I said "Gotcha", I meant that as in "understood" and not in an adversarial manner. Quite the opposite, actually, as this is a respectful thread which I believe both parties have enjoyed.
17 comments
[ 3.1 ms ] story [ 41.9 ms ] threadBut I think that the point of functional programming is to provide a layer of programming that exposes a clean API. You know: now side effects, no global variables etc..
And maybe: no if!
(Except infix/prefix)
Take a look here: http://blog.klipse.tech/klipse/2016/09/09/klipse-languages.h...
But unfortunately, itertools is not (yet?) supported by skulpt :(
While it doesn't use the spiffy lazy lists of itertools, and does have the typical "if x % n == 0" test, it does generalize easily to the "and print Baz every 37th number" case.
Treating a dictionary as an iterator automatically iterates over its .keys(), so you can remove the .keys() in fb.keys() and just map over fb itself.
>>> map(lambda x: x+x, {2: "who", 4: "do", 6: "we", 8: "appreciate"})
[16, 4, 8, 12]
A problem that this highlights is that the order in which the Fizz and Buzz and other strings get concatenated depends on the order of the underlying dictionary hash, which can be thought of as random. In Python 3 it even changes from run to run.
https://docs.python.org/3/whatsnew/3.3.html#summary-release-...
$ python3 -c 'print(list({"foo": "bar", "baz": "qux"}))'
['foo', 'baz']
$ python3 -c 'print(list({"foo": "bar", "baz": "qux"}))'
['baz', 'foo']
For predictable behavior across larger sets of divisors, and for consistent behavior on Python 3, you'd probably want to use collections.OrderedDict.
However, below is another version which employs idioms more commonly found:
But still I prefer the clojure version using pattern matching over the scala one: http://blog.klipse.tech/clojure/2016/10/25/core-match.html#f...