fizzbuzz в хаскеле? - PullRequest
       9

fizzbuzz в хаскеле?

3 голосов
/ 05 августа 2011

Я пытаюсь написать 'fizzbuzz' в haskell, используя списочные выражения.

Почему не работает следующее и как оно должно быть?

[ 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 ]

39 голосов
/ 05 августа 2011

Это не действительно 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"; ваш код выглядит немного иначе.

11 голосов
/ 05 августа 2011

Прежде всего, вам не хватает else частей ваших if выражений. В Haskell if является выражением, а не утверждением, поэтому часть else является обязательной.

Во-вторых, понимание списка дает только значения, если все защитные выражения имеют значение True. Число от 1 до 20, равное 0 по модулю 3, 4 и 5, отсутствует, поэтому вы не получите результатов. Вместо этого вы захотите использовать || (логическое ИЛИ), чтобы объединить их.

В-третьих, в большинстве определений FizzBuzz требуется, чтобы вы возвращали сам номер, если он не соответствует ни одному из других условий. В этом случае вам нужно будет использовать show для преобразования числа в String.

4 голосов
/ 06 августа 2011

Вот еще одна версия, которая может быть расширена до произвольного числа замен:

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
3 голосов
/ 05 августа 2011

В целом, полезно также указать ошибку, а не только код.

Но в этом случае проблема заключается в том, что для каждого if требуется условие else.Помните, что оператор if - это просто выражение, поэтому обе ветви должны возвращать значение соответствующего типа.

Кстати, в коде есть несколько ошибок, но это единственноеошибка компилятора.

2 голосов
/ 30 июня 2015

Считыватель монад содержит решение, а также множество ценных идей и некоторые более интересные упражненияРешение скопировано здесь для тех, кто просто хочет его увидеть.

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
2 голосов
/ 30 июля 2013

С помощью некоторого разумного карри Кэлвин Боттомс сделал это в 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]]
2 голосов
/ 06 августа 2011

Вот ответ на традиционную проблему 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вызвать эту функцию из вашего понимания списка.Лучше опираться на небольшие лаконичные функции, чем пытаться решить их в одной более сложной функции.например,

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]]
1 голос
/ 05 августа 2011

Нет x, которое бы удовлетворяло условию деления на 3, 4 и 5 в диапазоне 1..20.

Следовательно, вы получили бы пустой список, если бы пример был синтаксически правильным, чтоэто не так.

...