通过幺半群理解FizzBuzz
FizzBuzz Through Monoids

原始链接: https://entropicthoughts.com/fizzbuzz-through-monoids

FizzBuzz 实现利用了保护序列模式,根据能否被 3、5 和 7 整除,有条件地生成 "fizz"、"buzz" 和 "zork" 字符串。每个整除检查如果为真则产生 `Just "字符串"`,如果为假则产生 `Nothing`。这些潜在的字符串被收集到一个列表中。 `mconcat` 利用 monoid 的 `<>` 运算符组合这些“可能”的字符串。如果存在任何字符串(即 `Just "字符串"`),则将其与其他现有字符串连接;否则,返回 `Nothing`。 最后,`fromMaybe (show i)` 转换结果:任何 `Nothing` 都被替换为原始数字 `i` 的字符串表示,而任何现有的连接字符串都将被保留。这确保始终返回 FizzBuzz 字符串或数字本身。程序然后迭代 1 到 100 的数字,应用此 FizzBuzz 函数,并打印每个数字的结果。

A Hacker News thread discusses using Monoids for FizzBuzz, inspired by a blog post. throwaway81523 criticizes the Monoid approach as overly complex and limiting, specifically for variations requiring spaces and an exclamation point. They suggest using lists and `intercalate` for better clarity and flexibility, providing a code snippet that handles Fizz, Buzz, and Bazz up to 110. kqr offers an alternative Monoid implementation using `newtype Words`, but concedes lists might be clearer. lgas shares a similar, simpler implementation from the past, noting its limitation to divisibility rules compared to the blog post's arbitrary predicates. The general consensus leans towards preferring lists over Monoids for this specific problem due to readability and adaptability.

原文

We have previously seen the guard-sequence pattern which sits at the core of this implementation. The expression

"fizz" <$ guard (rem i 3 == 0)

will evaluate to Just "fizz" whenever i is divisible with three, and in all other cases it evaluates to Nothing. Thus, if a number is not divisible by any of the three given, the list will evaluate to

[Nothing, Nothing, Nothing]

If a number is divisible by only five, but not three or seven, the list will be

[Nothing, Just "buzz", Nothing]

And if a number is divisible by, say, three and seven, but not five, the list will be

[Just "fizz", Nothing, Just "zork"]

These are smushed together by the mconcat from the Monoid interface, which uses the generic smushing operation <>. This behaves just as expected for our strings-that-might-not-exist: it concatenates them together if they do exist, otherwise it returns Nothing.

Whatever we get out of mconcat, we pass it to fromMaybe (show i) which replaces any Nothing values with the string representation of the number coming into the function, but passes through any actual values it receives intact. This is the full fizzbuzz function that converts a number to the correct textual representation.

To make it an actual program, we loop through all numbers [1..100], convert them with fizzbuzz, and print the result.

联系我们 contact @ memedata.com