我正在尝试使用列表推导在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]]
由于
答案 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)来组合它们。
第三,如果不满足任何其他条件,FizzBuzz的大多数定义都希望您返回该数字。在这种情况下,您需要使用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对传统FizzBuzz问题的回应。
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整除。
因此,如果示例语法正确,则会得到一个空列表,而不是。