首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何在F#中编写Fizzbuzz

如何在F#中编写Fizzbuzz
EN

Stack Overflow用户
提问于 2010-03-11 13:15:29
回答 11查看 5.4K关注 0票数 24

我目前正在学习F#,并且已经尝试过FizzBuzz的一个(非常)简单的例子。

这是我最初的尝试:

代码语言:javascript
运行
复制
for x in 1..100 do 
    if x % 3 = 0 && x % 5 = 0 then printfn "FizzBuzz"  
    elif x % 3 = 0 then printfn "Fizz"
    elif x % 5 = 0 then printfn "Buzz"
    else printfn "%d" x

使用F#来解决这个问题,有什么解决方案可以更优雅/更简单/更好(解释原因)?

注: FizzBuzz问题是通过数字1到100,3的倍数打印FizzBuzz,5的倍数打印Buzz,3和5的倍数打印Fizz。否则,将显示简单的数字。

谢谢:)

EN

回答 11

Stack Overflow用户

回答已采纳

发布于 2010-03-11 13:20:44

我认为你已经有了“最好”的解决方案。

如果你想展示更多的功能/F#,你可以这样做。

代码语言:javascript
运行
复制
[1..100] 
|> Seq.map (function
    | x when x%5=0 && x%3=0 -> "FizzBuzz"
    | x when x%3=0 -> "Fizz"
    | x when x%5=0 -> "Buzz"
    | x -> string x)
|> Seq.iter (printfn "%s")

并使用列表、序列、映射、iter、模式和部分应用程序。

代码语言:javascript
运行
复制
[1..100]    // I am the list of numbers 1-100.  
            // F# has immutable singly-linked lists.
            // List literals use square brackets.

|>          // I am the pipeline operator.  
            // "x |> f" is just another way to write "f x".
            // It is a common idiom to "pipe" data through
            // a bunch of transformative functions.

   Seq.map  // "Seq" means "sequence", in F# such sequences
            // are just another name for IEnumerable<T>.
            // "map" is a function in the "Seq" module that
            // applies a function to every element of a 
            // sequence, returning a new sequence of results.

           (function    // The function keyword is one way to
                        // write a lambda, it means the same
                        // thing as "fun z -> match z with".
                        // "fun" starts a lambda.
                        // "match expr with" starts a pattern
                        // match, that then has |cases.

    | x when x%5=0 && x%3=0 
            // I'm a pattern.  The pattern is "x", which is 
            // just an identifier pattern that matches any
            // value and binds the name (x) to that value.
            // The "when" clause is a guard - the pattern
            // will only match if the guard predicate is true.

                            -> "FizzBuzz"
                // After each pattern is "-> expr" which is 
                // the thing evaluated if the pattern matches.
                // If this pattern matches, we return that 
                // string literal "FizzBuzz".

    | x when x%3=0 -> "Fizz"
            // Patterns are evaluated in order, just like
            // if...elif...elif...else, which is why we did 
            // the 'divisble-by-both' check first.

    | x when x%5=0 -> "Buzz"
    | x -> string x)
            // "string" is a function that converts its argument
            // to a string.  F# is statically-typed, so all the 
            // patterns have to evaluate to the same type, so the
            // return value of the map call can be e.g. an
            // IEnumerable<string> (aka seq<string>).

|>          // Another pipeline; pipe the prior sequence into...

   Seq.iter // iter applies a function to every element of a 
            // sequence, but the function should return "unit"
            // (like "void"), and iter itself returns unit.
            // Whereas sequences are lazy, "iter" will "force"
            // the sequence since it needs to apply the function
            // to each element only for its effects.

            (printfn "%s")
            // F# has type-safe printing; printfn "%s" expr
            // requires expr to have type string.  Usual kind of
            // %d for integers, etc.  Here we have partially 
            // applied printfn, it's a function still expecting 
            // the string, so this is a one-argument function 
            // that is appropriate to hand to iter.  Hurrah!
票数 58
EN

Stack Overflow用户

发布于 2010-03-12 09:15:27

我的例子只是对'ssp‘发布的代码的一个小小的改进。它使用参数化的活动模式(以除数为参数)。这里有一个更深入的解释:

下面定义了一个活动模式,稍后我们可以在match表达式中使用该模式来测试值i是否可以被值divisor整除。当我们写下:

代码语言:javascript
运行
复制
match 9 with
| DivisibleBy 3 -> ...

...it表示值'9‘将作为i传递给下面的函数,而值3将作为divisor传递。名称(|DivisibleBy|_|)是一种特殊的语法,这意味着我们声明了一个活动模式(该名称可以出现在->左侧的match中。|_|位意味着模式可能失败(当值不能被divisor整除时,我们的示例将失败)

代码语言:javascript
运行
复制
let (|DivisibleBy|_|) divisor i = 

  // If the value is divisible, then we return 'Some()' which
  // represents that the active pattern succeeds - the '()' notation
  // means that we don't return any value from the pattern (if we
  // returned for example 'Some(i/divisor)' the use would be:
  //     match 6 with 
  //     | DivisibleBy 3 res -> .. (res would be asigned value 2)
  // None means that pattern failed and that the next clause should 
  // be tried (by the match expression)
  if i % divisor = 0 then Some () else None 

现在我们可以迭代所有的数字,并使用match (或使用Seq.iter或其他一些技术,如其他答案中所示)将它们与模式(我们的活动模式)进行匹配:

代码语言:javascript
运行
复制
for i in 1..100 do
  match i with
  // & allows us to run more than one pattern on the argument 'i'
  // so this calls 'DivisibleBy 3 i' and 'DivisibleBy 5 i' and it
  // succeeds (and runs the body) only if both of them return 'Some()'
  | DivisibleBy 3 & DivisibleBy 5 -> printfn "FizzBuzz"
  | DivisibleBy 3 -> printfn "Fizz" 
  | DivisibleBy 5 -> printfn "Buzz" 
  | _ -> printfn "%d" i

有关F# active patterns、here is an MSDN documentation link的更多信息,但在您的例子中,任务相对简单……

票数 26
EN

Stack Overflow用户

发布于 2010-03-11 22:23:15

然而,F#风格的一种解决方案(即使用活动模式):

代码语言:javascript
运行
复制
let (|P3|_|) i = if i % 3 = 0 then Some i else None
let (|P5|_|) i = if i % 5 = 0 then Some i else None

let f = function
  | P3 _ & P5 _ -> printfn "FizzBuzz"
  | P3 _        -> printfn "Fizz"
  | P5 _        -> printfn "Buzz"
  | x           -> printfn "%d" x

Seq.iter f {1..100}
//or
for i in 1..100 do f i
票数 12
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/2422697

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档