2012-01-28 12 views
7

wciąż się uczę Haskell, a ja zastanawiałem się, czy jest tam mniej gadatliwy sposób wyrazić za pomocą poniższego komunikatu 1 wiersz kodu:FizzBuzz oczyszczania

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

produkuje: [(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") itp

Po prostu mam wrażenie, że walczę ze składnią bardziej, niż powinienem. Widziałem inne pytania na ten temat w Haskell, ale szukam najbardziej optymalnego sposobu wyrażenia tego w jednym oświadczeniu (próbując zrozumieć, jak lepiej pracować ze składnią).

+0

http://www.haskell.org/haskellwiki/index.php?title = & search = fizzbuzz & fulltext = Wyszukaj –

+0

@ Sergio, nie bądź głupi. Potrzebne są tylko 2 doktoraty: P –

Odpowiedz

7

Jeśli nalegać na jedną wkładką:

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

wydaje się to bardzo zbliżone do tego, o czym myślę. Jakikolwiek sposób ugotować to tak, aby concat nie był potrzebny? Czytając to logicznie, konkat jest dla mnie formą hałasu behawioralnego. Czyta: utwórz tablicę, która wykonuje kroki od 1 do 100, z każdym elementem będącym konkatentem z dwiema tablicami zawierającymi pojedynczy element łańcucha wciśnięty na siebie (..etc). –

+2

Nawiasem mówiąc, listy w Haskell są pojedynczymi połączonymi listami, a nie tablicami; tablice (takie jak te w pakietach [array] (http://hackage.haskell.org/package/array) i [vector] (http://hackage.haskell.org/package/vector) są używane stosunkowo rzadko w porównaniu do innych języków. – ehird

+0

oznacza to jako odpowiedź, ponieważ najlepiej sprawdza się jako instrukcja 1-liniowa bez instrukcji złożonych, takich jak "gdzie". Podoba mi się również, że wyrażenie jest zbudowane całkowicie w definicji listy, co nadaje mu bardziej semantyczny kontekst. –

4

Jak chodzi o ...

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

Według tych samych zasad jak larsmans' odpowiedź:

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

, to jest to, co właśnie zrobiłem: '[(x," Fizz "\" ifDivisibleBy \ 3 ++ "Buzz" \ "ifDivisibleBy \' 5) | x <- [1..100], let ifDivisibleBy s n = if x \ 'mod \ 'n == 0 then s else" "]' – rampion

2

mogłem” t oprzeć się w innym kierunku i uczynić go bardziej skomplikowanym. Spójrz, nie 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

moja głowa eksplodowała, dzięki –

1

myślę, dlaczego czujesz się jak walczą składnia jest, ponieważ jesteś mieszanie zbyt wiele rodzajów.

Zamiast próbować wydrukować:

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

Wystarczy pomyśleć ciągów drukowania:

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

Moja próba:

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"...] 

W celu przekształcenia int na string użyć :

show x 
10

Musimy nie stinkin' mod ...

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

lub nieco krótsza

import Data.Function(on) 

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

Albo brute force sposób:

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

Writer monada może wyglądać dobrze (jeśli nie podoba Ci się concat):

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

Nie jest to jednak szczególnie zwięzłe.

1

Tylko dla studiowania

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

produkuje

["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"] 
Powiązane problemy