4

リスト内包表記を使用して、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 ]
4

8 に答える 8

38

これは有効な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」で機能します。コードが少し違うようです。

于 2011-08-05T13:57:27.323 に答える
11

まず第一に、あなたはあなたの表現のelse部分を失っています。ifHaskellでは、ifはステートメントではなく式であるため、このelse部分は必須です。

次に、リスト内包表記は、すべてのガード式がに評価された場合にのみ値を生成しますTrue。3、4、および5を法として0である1から20までの数値はないため、結果は得られません。||代わりに、(論理OR)を使用してそれらを組み合わせることができます。

第三に、FizzBu​​zzのほとんどの定義では、他の条件のいずれも満たさない場合は、番号自体を返す必要があります。その場合はshow、数値をに変換するために使用する必要がありますString

于 2011-08-05T13:56:34.453 に答える
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'where句にインライン化することもできますがfizzbuzz、別の関数の方がテストしやすいことがわかりました。

次のように実行できます。

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

または追加の置換を使用して:

λ> mapM_ putStrLn $ map (fizzbuzz [(3, "fizz"), (5, "buzz"), (7, "dazz")]) [19..24]
19
buzz
fizzdazz
22
23
fizz
于 2011-08-06T14:01:20.317 に答える
3

一般に、コードだけでなく、エラーが発生した場合にも役立ちます。

しかし、この場合、問題はすべてに句ifが必要なことです。ステートメントは単なる式であるため、両方のブランチが適切なタイプの値を返す必要があることに注意してくださいelseif

ちなみに、コードにはいくつかのバグがありますが、それが唯一のコンパイラエラーです。

于 2011-08-05T13:51:52.297 に答える
2

これは、リスト内包とガードを使用した従来の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して、リスト内包表記からその関数を呼び出すことを恐れないでください。もう1つの複雑な関数で解決しようとするよりも、小さな簡潔な関数に基づいて構築する方が適切です。例えば

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]]
于 2011-08-05T23:45:48.023 に答える
2

いくつかの賢明なカリー化の助けを借りて、CalvinBottomsは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]]
于 2013-07-29T21:41:01.200 に答える
2

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
于 2015-06-30T18:25:21.280 に答える
1

1..20の範囲で3、4、および5で割り切れる条件を満たすxはありません。

したがって、例が構文的に正しい場合は空のリストが表示されますが、そうではありません。

于 2011-08-05T13:52:32.083 に答える