哈斯克尔的fizzbuzz?

时间:2011-08-05 13:42:20

标签: haskell fizzbuzz

我正在尝试使用列表推导在haskell中编写'fizzbuzz'。

为什么以下工作没有,应该怎么做?

[ if x `mod` 5 == 0 then "BUZZFIZZ"
  if x `mod` 3 == 0 then "BUZZ" 
  if x `mod` 4 == 0 then "FIZZ" | x <- [1..20], 
    x `mod` 3 == 0, 
    x `mod` 4 == 0, 
    x `mod` 5 == 0 ]

- 更新 -

确定这有效:

[ if x `mod` 5 == 0 then "BUZZFIZZ"
        else
          if x `mod` 3 == 0 then "BUZZ" 
          else
          if x `mod` 4 == 0 then "FIZZ" else show x
          | x <- [1..25]]

由于

8 个答案:

答案 0 :(得分:39)

这不是有效的Haskell。 else分支在if ... then ... else中不是可选的。而不是使用if,这似乎是使用case语句的好机会。

case (x `rem` 3, x `rem` 5) of
  (0,0) -> "fizzbuzz"
  (0,_) -> "fizz"
  (_,0) -> "buzz"
  _     -> show x

此片段适用于传统的“fizzbuzz”;你的代码似乎略有不同。

答案 1 :(得分:11)

首先,您错过了else表达式的if部分。在Haskell中,if是表达式,而不是语句,因此else部分是必需的。

其次,如果 all 保护表达式计算为True,则列表推导仅生成任何值。 1到20之间没有数字,模数为3,4和5,因此您将得不到任何结果。您将要使用||(逻辑OR)来组合它们。

第三,如果不满足任何其他条件,FizzBu​​zz的大多数定义都希望您返回该数字。在这种情况下,您需要使用show将数字转换为String

答案 2 :(得分:4)

这是另一个可以扩展到任意数量的替换的版本:

fizzbuzz' :: [(Integer, String)] -> Integer -> String
fizzbuzz' ss n = foldl (\str (num, subst) -> if n `mod` num == 0 then str ++ subst else str ++ "") "" ss

fizzbuzz :: [(Integer, String)] -> Integer -> String
fizzbuzz ss n = if null str then show n else str
  where str = fizzbuzz' ss n

您可以在fizzbuzz'的{​​{1}}子句中内联where,但我发现一个单独的函数更容易进行测试。

您可以像这样运行:

fizzbuzz

或者有额外的替换:

λ> mapM_ putStrLn $ map (fizzbuzz [(3, "fizz"), (5, "buzz")]) [9..15]
fizz
buzz
11
fizz
13
14
fizzbuzz

答案 3 :(得分:3)

一般情况下,如果您也提供错误,而不仅仅是代码,这会有所帮助。

但在这种情况下,问题是每个if都需要一个else子句。请记住,if语句只是一个表达式,因此两个分支都必须返回适当类型的值。

顺便说一下,你的代码中有几个bug,但这是唯一的编译器错误。

答案 4 :(得分:2)

以下是使用list comprehension + guards对传统FizzBu​​zz问题的回应。

fizzbuzz = [fb x| x <- [1..100]]
    where fb y
        | y `mod` 15 == 0 = "FizzBuzz"
        | y `mod` 3  == 0 = "Fizz"
        | y `mod` 5  == 0 = "Buzz"
        | otherwise  = show y

或者不要害怕将where子句移动到单独的简洁函数中以评估x,然后从列表推导中调用该函数。建立在简洁的小功能上比在一个更复杂的功能中尝试解决它更好。 e.g。

fizzval x
    | x `mod` 15 == 0 = "FizzBuzz"
    | x `mod` 3  == 0 = "Fizz"
    | x `mod` 5  == 0 = "Buzz"
    | otherwise  = show x

fizzbuzz = [fizzval x| x <- [1..100]]

答案 5 :(得分:2)

在一些明智的曲线的帮助下,Calvin Bottoms以77个角色做到了。

http://freshbrewedcode.com/calvinbottoms/2012/02/25/fizzbuzz-in-haskell/

[max(show x)(concat[n|(f,n)<-[(3,"Fizz"),(5,"Buzz")],mod x f==0])|x<-[1..25]]

答案 6 :(得分:2)

The Monad Reader包含解决方案以及许多有价值的见解和一些有趣的练习。这里的解决方案被复制给那些只想看的人。

fizzbuzz :: Int -> String
fizzbuzz n = (test 3 "fizz" . test 5 "buzz") id (show n)
    where test d s x | n `mod` d == 0 = const (s ++ x "")
                     | otherwise      = x

答案 7 :(得分:1)

没有x可以使条件在1..20范围内被3,4和5整除。

因此,如果示例语法正确,则会得到一个空列表,而不是。