7行代码来编写Elixir中的Fizz-Buzz游戏原理

编码FizzBu​​zz游戏后端原则

本文全部涉及在FizzBu​​zz中编码隐式条件。 这使您可以遍历代码行,这些代码以不同的语法提供相似的输出。

这是针对Elixir的完整初学者的。 但是,最后这将提供更多信息。

当您使用google时,您会发现以下有关FizzBu​​zz的短语。

FizzBu​​zz是一项非常简单的编程任务,用于软件开发人员的求职面试中,以确定求职者是否可以实际编写代码

Fizz嗡嗡声是一个小组文字游戏,儿童可以教他们有关分裂的知识。 玩家轮流进行递增计数,用“ fizz”一词替换任何可被整除的数字,用“ buzz”一词替换可被五整除的任何数字,如果被FizzBu​​zz词一分为三可整除,则仅打印数字本身。

这就是FizzBu​​zz的全部内容。 哦..您终于知道了FizzBu​​zz是什么。 继续摇摆…

我们只是简单地打印范围内的数字,并使用游戏协议将其替换为单词Fizz,Buzz和FizzBu​​zz。

该写代码了……

泡沫部分

在这里,我用FizzBuzz命名了模块,当然每个人都做同样的FizzBuzz ,并编写了play/2函数。

首先,我们只是打印范围内的数字,然后看它是如何工作的。

  defmodule FizzBu​​zz做 
def播放(最小,最大)
Enum.each(min..max,fn(num)-> IO.puts num end)
结束
结束

播放/ 2

该函数采用两个数字作为输入范围内的技术最大值和最小值。 因此,我们可以通过../2宏创建一个范围。

最小。最大

范围在内部以结构表示。 范围实现了Enumerable协议,这意味着Enum模块中的功能可用于处理范围。

您可以在i/1的帮助下检查已实施的协议

 我1..2 

因此,我们借助Enum模块中的each函数来遍历整个范围并打印数字。

fn(num)-> IO.puts num end

在这里,我们使用匿名函数通过调用IO.puts内部的IO.puts来打印数字。

功能输入值的模式匹配

在这里,我们将编写另一个具有相同名称play函数,但是这次只需要一个输入play/1 。 根据OOP,它称为方法重载。

这就是代码的外观。

  defmodule FizzBu​​zz做 
def播放(最小,最大)
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,3)== 0时结束def play(num)
IO.puts“嘶嘶声”
结束

变化:

我们创建了一个用于打印的函数,而不是在匿名函数内调用IO.puts 。 在play/1的函数定义中, when满足游戏条件when ,我们使用了Elixir 保护子句。

如果该数字可被三整除,则余数将为0 。 因此,我们使用rem/2函数获取余数,并使用==检查表达式的真值。 如果true值为true ,它将运行函数定义,否则将不运行定义。

现在复制代码并将其粘贴到iex 。 它编译良好。

现在,将播放功能调用为

  iex> FizzBu​​zz.play 1,20 

您将看到运行时错误。 它编译良好,但是在运行时出现错误。

这就是错误的外观。

故障排除

我们的代码有什么问题?

范围1..20的第一个值将是1因为范围总是包含在内的。

函数调用的第一次迭代看起来像

 枚举-fn(1)-> play(1)结束 

此处, play功能是使用值1触发的,但是,保护子句表达式rem(1, 3)==0会导致结果为false因此,该功能子句与传递的值不匹配。

因此,我们需要编写另一个print函数来负责打印不能被3整除的数字,这就是代码的外观。

  defmodule FizzBu​​zz做def play(min,max)做 
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,3)== 0时结束def play(num)
IO.puts“嘶嘶声”
结束def play(num)做
IO数量
结束

现在尝试通过复制粘贴上面的代码行到iex进行尝试,然后将play函数称为FizzBuzz.play 1,20

您将看到被三次迭代整除的数字将打印Fizz而不是打印数字。

像Fizz一样,我们必须添加另一个带有play/1子句的play/1函数,该函数带有保护子句以检查5的可除性。

让我们看看更新的代码

  defmodule FizzBu​​zz做def play(min,max)做 
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,3)== 0时结束def play(num)
IO.puts“嘶嘶声”
当rem(num,5)== 0时结束def play(num)
IO.puts“嗡嗡声”
结束def play(num)做
IO数量
结束

像Fizz和Buzz一样,我们可以考虑两个数字的LCM (最小公倍数),以3和5检验数字的可除性。 3和5的LCM为15。因此,如果数字可以被15整除,那么它可以被3和5整除。

让我们添加另一个功能。

  defmodule FizzBu​​zz做def play(min,max)做 
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,3)== 0时结束def play(num)
IO.puts“嘶嘶声”
当rem(num,5)== 0时结束def play(num)
IO.puts“嗡嗡声”
当rem(num,15)== 0时结束def play(num)
IO.puts“ FizzBu​​zz”
结束def play(num)做
IO数量
结束

现在,复制并粘贴以上代码行,然后运行play/2函数。

令我们惊讶的是,它在迭代15时打印Fizz而不是FizzBu​​zz

我们的代码有什么问题?

故障排除

  defmodule FizzBu​​zz dodef播放(最小,最大) 
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,3)== 0时执行enddef play(num)
IO.puts“嘶嘶声”
当rem(num,5)== 0时执行enddef play(num)
IO.puts“嗡嗡声”
当rem(num,15)== 0时,enddef play(num)
IO.puts“ FizzBu​​zz”
enddef play(num)做
IO数量
结束

让我们以15次迭代来解释代码

 每个枚举-#15play(15) 
-
当rem(15,3)== 0时播放(15)

表达式rem(15, 3)==0将得出true 。 因此,它只是打印Fizz并跳至下一个迭代。

因此,我们需要重新排序功能。 具有保护子句rem(num, 15) == 0play/1函数应位于所有其余函数之上。 因此,首先检查15的除数,然后再检查3,然后再检查5。

让我们更新代码。

  defmodule FizzBu​​zz dodef播放(最小,最大) 
Enum.each(min..max,fn(num)-> play(num)end)
当rem(num,15)== 0时,enddef play(num)
IO.puts“ FizzBu​​zz”
当rem(num,3)== 0时执行enddef play(num)
IO.puts“嘶嘶声”
当rem(num,5)== 0时执行enddef play(num)
IO.puts“嗡嗡声”
当rem(num,15)== 0时,enddef play(num)
IO.puts“ FizzBu​​zz”
enddef play(num)做
IO数量
结束

现在,在iex复制并粘贴以上代码行,并运行FizzBuzz.play 1, 20 iex函数。

欢呼! 我们完成了代码逻辑。

但是,文章标题指出,我们需要用七(7)行代码来做到这一点。

让我们改进代码。

我们还有什么可以改进的?

无需每次都复制粘贴到iex ,我们可以创建文件fizz_buzz.ex并将代码粘贴到其中。

现在运行命令

  iex fizz_buzz.ex 

您必须位于文件所在的同一目录中。

否则,您必须以

  IEX路径/到/文件/ fizz_buzz.ex 

它将模块加载到新的iex会话中。 您仍然可以检查模块是否已加载Code.ensure_loaded FizzBuzz

可以使用r FizzBuzz重新编译文件fizz_buzz.ex的更改。 在这里r重新编译并重新加载给定的模块。

到目前为止,删除空的新行后,我们的代码由20行组成。

现在我们必须改进代码,使其看起来比以前更好。

替代品

在elixir中,我们可以将匿名函数fn(num)-> play(num) end替换为&(play(&1))

所以更新线

保存文件并使用r fizz_buzz.ex重新编译

我们可以通过传递函数名称并使其迭代遍历each函数的范围来简化此过程

所以,更新行

 枚举每个(min..max,&(play(&1))) 

 每个枚举(最小。最大,&play / 1) 

现在,使用更新保存文件,然后重新编译并对其进行测试。 它仍然有效。

Elixir中的单行功能

如果您清楚地观察到代码逻辑,则我们的大多数函数定义都是一行。 因此,我们可以避免do .. end块。 我们可以使用do:单行样式更新函数定义。

  #之前 
当rem(num,15)== 0时def play(num)
IO.puts“ FizzBu​​zz”
在rem(num,3)== 0的情况下更新def play(num,3)之后执行end#,请执行:IO.puts“ FizzBu​​zz”

同样,我们将使用单线样式代码库更新其余的函数定义。

这是更新后的样子

  defmodule FizzBu​​zz做 
def播放(最小,最大),执行:枚举每个(最小。最大,&play / 1)
当rem(num,15)== 0时执行def play(num),请执行:IO.puts“ FizzBu​​zz”
def play(num)当rem(num,3)== 0时,执行:IO.puts“ Fizz”
当rem(num,5)== 0时执行def play(num),请执行:IO.puts“ Buzz”
def play(num),执行:IO.puts num
结束

繁荣! 我们分7行开发了代码逻辑。 你真棒…

本文最初发布于Ahamtech博客

快乐编码…