简体   繁体   English

在Haskell中使用守卫编写乘积函数

[英]Writing a product function using guards in Haskell

I need to write the function product in two ways: 我需要以两种方式编写函数product

  1. Using Guards 使用卫兵
  2. Using if-then-else 使用if-then-else

So that the function return the product of m through n. 使函数返回m到n的乘积。

example: 例:

product 3 5

returns 3*4*5 = 60 返回3 * 4 * 5 = 60

Thanks 谢谢

This sounds like a homework problem so instead of just dropping code on you, let's work through the problem: 这听起来像是一个家庭作业问题,所以让我们着手解决这个问题,而不仅仅是在您身上放下代码:

Type Signature 类型签名

Haskell is a functional language with strong typing so it is probably best to start by writing the type signature of our function. Haskell是一种具有强类型的功能语言,因此最好从编写我们函数的类型签名开始。 Your example shows two integer arguments and an integer return value. 您的示例显示了两个整数参数和一个整数返回值。 We code this as: 我们将其编码为:

product :: Int->Int->Int

This reads as " product is a function that takes two Int s and returns an Int ." 读作“ product是一个接受两个Int并返回一个Int的函数”。 (there are other more correct ways to read this but that is for another day) (还有其他更正确的阅读方式,但这是另一天的事情)

Recursion 递归

we are going to use a common pattern in Haskell. 我们将在Haskell中使用通用模式。 Because we need to keep track of intermediate values in this case the partial product we will write a second function product' that will take an extra parameter, the running product. 因为在这种情况下我们需要跟踪中间值的部分乘积,所以我们将编写第二个函数product' ,该product'将带有一个额外的参数,即运行乘积。

product' :: Int->Int->Int->Int
product' accumulator current final = product' (accumulator*current) (current+1) final

At every iteration this will take the most recent accumulated value multiply by current and pass that as the new accumulator, it will take current and add 1 to it passing it as the new current, and will pass final unchanged. 在每次迭代中,这将采用最新的累加值乘以电流,并将其作为新累加器传递,它将采用电流并对其加1,将其作为新电流传递,并最终传递不变。 To get it started we write our original function: 首先,我们编写原始功能:

product i f = product' 1 i f

or in points-free notation 或采用无分符号

product = product' 1

The problem is the product' code will loop forever. 问题在于product'代码将永远循环。 We need a way to stop when we current is greater then final. 当电流大于最终值时,我们需要一种停止的方法。

Guards 守卫

Rather then rewrite the book on guard patterns I'll send you to the book . 宁可改写关于守卫模式的书,我也会带您到这本书 In short they let you a boolean before you do something. 简而言之,在您做某事之前,它们会让您布尔值。 We'll use them to stop our recursion. 我们将使用它们来停止递归。

product' :: Int->Int->Int->Int
product' accumulator current final 
    | current <= final = product' (accumulator*current) (current+1) final
    | otherwise = accumulator

So long as current is less than or equal to final we continue to recurse once it's not the final answer is in accumulator. 只要current小于或等于final ,一旦不是最终答案,我们就会继续递归。

If-Then-Else 如果-然后-其他

Guards can be replaced with if constructs (perhaps deeply nested) in a mechanical fashion. 可以用机械方式将if构造(可能是深度嵌套)替换为警卫。

product' :: Int->Int->Int->Int
product' accumulator current final = 
  if current <= final 
    then product' (accumulator*current) (current+1) final
    else accumulator

Final Thoughts 最后的想法

Don't write code like this. 不要写这样的代码。 There are a number of wonderfully generic higher level function that do just these types of things. 有许多出色的通用高级功能可以执行这些类型的事情。 Here is just one better way to write product: 这只是编写产品的一种更好的方法:

product i f = foldl (*) 1 [i..f]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM