2012-01-28 2 views
7

Я все еще учусь Haskell, и мне было интересно, если есть менее многословным способ выразить ниже заявление, используя 1 строку кода:FizzBuzz очистки

map (\x -> (x, (if mod x 3 == 0 then "fizz" else "") ++ 
if mod x 5 == 0 then "buzz" else "")) [1..100] 

производит: [(1,""),(2,""),(3,"fizz"),(4,""),(5,"buzz"),(6,"fizz"),(7,""),(8,""),(9,"fizz"),(10,"buzz"),(11,""),(12,"fizz"),(13,""),(14,""),(15,"fizzbuzz"),(16,""),(17,""),(18,"fizz"),(19,""),(20,"buzz"),(21,"fizz"),(22,""),(23,""),(24,"fizz"),(25,"buzz"),(26,""),(27,"fizz"),(28,""),(29,""),(30,"fizzbuzz") и т.д.

Мне просто кажется, что я борюсь с синтаксисом больше, чем должен. Я видел другие вопросы для этого в Haskell, но я ищу наиболее оптимальный способ выразить это в одном утверждении (пытаясь понять, как лучше работать с синтаксисом).

+0

http://www.haskell.org/haskellwiki/index.php?title = & search = fizzbuzz & fulltext = Поиск –

+0

@ Серхио, не будь глупым. Вам просто нужны 2 доктора: P –

ответ

7

Если вы настаиваете на однострочника:

[(x, concat $ ["fizz" | mod x 3 == 0] ++ ["buzz" | mod x 5 == 0]) | x <- [1..100]] 
+0

это кажется очень близким к тому, что я думаю. Любой способ кипятить это так, чтобы конкат не нужен? Читая это логически, concat - это форма поведенческого шума для меня. Он читает: создайте массив, который выполняет шаги от 1 до 100, причем каждый элемент является concat с двумя массивами, содержащими один строковый элемент, наложенный друг на друга (..etc). –

+2

Кстати, списки в Haskell - это списки, связанные друг с другом, а не массивы; массивы (например, в пакетах [array] (http://hackage.haskell.org/package/array) и [vector] (http://hackage.haskell.org/package/vector)) используются относительно нечасто по сравнению с другими языками. – ehird

+0

, отмечая это как ответ, поскольку он читает лучшее как заявление с 1 строкой без рецептов, например «где». Мне также нравится, что выражение построено полностью внутри определения списка, придавая ему более смысловой контекст. –

4

Как про ...

fizzBuzz = [(x, fizz x ++ buzz x) | x <- [1..100]] 
    where fizz n | n `mod` 3 == 0 = "fizz" 
       | otherwise  = "" 
     buzz n | n `mod` 5 == 0 = "buzz" 
       | otherwise  = "" 
1

В том же ключе, как larsmans' ответ:

fizzBuzz = [(x, f 3 "fizz" x ++ f 5 "buzz" x) | x <- [1..100]] 
    where f k s n | n `mod` k == 0 = s 
       | otherwise  = "" 
+0

, что по существу то, что я только что сделал: '[(x," Fizz "\' ifDivisibleBy \ '3 ++" Buzz "\' ifDivisibleBy \ '5) | x <- [1..100], пусть ifDivisibleBy s n = if x \ 'mod \' n == 0, затем s else ""] ' – rampion

2

»не мог т сопротивляться переходу в другом направлении и усложнять его. Посмотрите, не mod ...

merge [email protected]([email protected](ia,sa):as') [email protected]([email protected](ib,sb):bs') = 
    case compare ia ib of 
    LT -> a : merge as' bs 
    GT -> b : merge as bs' 
    EQ -> (ia, sa++sb) : merge as' bs' 
merge as bs = as ++ bs 

zz (n,s) = [(i, s) | i <- [n,2*n..]] 
fizzBuzz = foldr merge [] $ map zz [(1,""), (3,"fizz"), (5,"buzz")] 
+1

моя голова взорвалась, спасибо –

1

Я не думаю, что причина, почему вы чувствуете, как вы боретесь синтаксис, потому что вы смешиваете слишком много типов.

Вместо того, чтобы пытаться печатать:

[(1, ""), (2,""), (3,"Fizz")...] 

Подумать только печатных строк:

["1","2","Fizz"...] 

Моя попытка:

Prelude> let fizzBuzz x | x `mod` 15 == 0 = "FizzBuzz" | x `mod` 5 == 0 = "Buzz" | x `mod` 3 == 0 = "Fizz" | otherwise = show x 
Prelude> [fizzBuzz x | x <-[1..100]] 

["1","2","Fizz","4","Buzz","Fizz","7","8","Fizz","Buzz","11","Fizz","13","14","FizzBuzz"...] 

Для того, чтобы преобразовать Int в строку вы используете :

show x 
10

Мы не нуждаются в stinkin' mod ...

zip [1..100] $ zipWith (++) (cycle ["","","fizz"]) (cycle ["","","","","buzz"]) 

или чуть короче

import Data.Function(on) 

zip [1..100] $ (zipWith (++) `on` cycle) ["","","fizz"] ["","","","","buzz"] 

Или перебором путь:

zip [1..100] $ cycle ["","","fizz","","buzz","fizz","","","fizz","buzz","","fizz","","","fizzbuzz"] 
0

Writer монада может выглядеть красиво (если вам не нравится concat):

fizzBuzz = [(x, execWriter $ when (x `mod` 3 == 0) (tell "fizz") >> when (x `mod` 5 == 0) (tell "buzz")) | x <- [1..100]] 

Это не особенно лаконично.

1

Только для изучения

zipWith (\a b -> b a) (map show [1..100]) $ cycle [id,id,const "fizz",id,const "buzz",const "fizz",id,id,const "fizz",const "buzz",id,const "fizz",id,id,const "fizzbuzz"] 

производит

["1","2","fizz","4","buzz","fizz","7","8","fizz","buzz","11","fizz","13","14","fizzbuzz","16","17","fizz","19","buzz","fizz","22","23","fizz","buzz","26","fizz","28","29","fizzbuzz","31","32","fizz","34","buzz","fizz","37","38","fizz","buzz","41","fizz","43","44","fizzbuzz","46","47","fizz","49","buzz","fizz","52","53","fizz","buzz","56","fizz","58","59","fizzbuzz","61","62","fizz","64","buzz","fizz","67","68","fizz","buzz","71","fizz","73","74","fizzbuzz","76","77","fizz","79","buzz","fizz","82","83","fizz","buzz","86","fizz","88","89","fizzbuzz","91","92","fizz","94","buzz","fizz","97","98","fizz","buzz"]