3 ms·
from functools import partial def rem(i, n, message): return message if not (i % n) else '' [(''.join([ partial(rem, message='fizz', n=3)(i),
by 101km 9y ago
from functools import partial
def rem(i, n, message):
return message if not (i % n) else ''
[(''.join([
partial(rem, message='fizz', n=3)(i),
partial(rem, message='buzz', n=5)(i)
]) or i) for i in range(1,101)]
vs
{-# LANGUAGE MonadComprehensions #-}
module Main where
import Data.Monoid (mappend)
import Data.Maybe (fromMaybe, listToMaybe, maybe)
import System.Environment (getArgs)
fizzbuzz i = fromMaybe (show i) $ mappend ["fizz" | i `rem` 3 == 0]
["buzz" | i `rem` 5 == 0]
-- mapM_ is our iterator, putStrLn writes to console.
main = mapM_ putStrLn [ fizzbuzz i | i <- [1..100] ]
- KirinDave 9y agoAs the author of the article, I feel like you've missed the point of this article if you're writing a "vs" post. The important point here is that monoids make this easier and less full of unique logic. The code you've posted here is clever and thoughtful, but still commits to the same "we don't abstract over monoids" problem I identified. You saved 4 lines over other versions and probably lost clarity in your quest for that. It's worth noting that you are leveraging a built monoid: strings. '' = mzero and join is your + operation.
- 101km 9y agoSorry, it is very early in the morning so I'm still waking up. I didn't mean anything by the groggy 'vs' other than a rosetta syntax comparison to Python. With that being said, I don't think my snippet lost clarity and is functionally (har har) equivalent to the Haskell. I believe where Haskell would shine is if the mappend operated on a more complex type than a regular string, but honestly I've only started reading learn you a Haskell two days ago so maybe I'm missing something deeper? Edit: I guess you could say Python strings are monoids and maybe works on ''.
- KirinDave 9y agoFair enough. Sorry, last time this was posted here we had a lot of those.
- vidarh 9y agoI think the responses you get here is largely due to the "language jumping" which instantly turns it into a language comparison. If you'd stuck to one language, and implemented the "machinery" in that, it'd perhaps be clearer that the point wasn't C/Python/Ruby vs. Haskell. E.g. here's a generic version in Ruby that to keep it simple just treats an Array as Maybe, with the empty Array as Nothing, giving us mappend and fromMaybe (we could make this more convoluted with a lazy "mappend" too, but it'd make the code even more un-Rubyish) like these: def mappend(*args) args.map(&:call).compact; end def fromMaybe(default); [yield].map{|m| m.empty? ? default : m}.first; end And so fizzbuzz becomes: def fizzbuzz(i) fromMaybe([i]) { mappend( -> { i % 3 == 0 ? "Fizz" : nil }, -> { i % 5 == 0 ? "Buzz" : nil }) } end (1..100).each {|i| puts(fizzbuzz(i).join) } And just as clear and extensible as the Haskell version. I think the issue with using this as an example is compounded by making it one where you can make the lambda's generic over a simple hash lookup, as well, which makes it easy to overlook that the above can also handle more divergent rules (e.g. ones not relying on remainder, for example)