【问题标题】:FizzBuzz cleanupFizzBu​​zz 清理
【发布时间】:2012-02-21 07:07:40
【问题描述】:

我还在学习 Haskell,我想知道是否有一种不那么冗长的方式来使用 1 行代码来表达以下语句:

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 中看到过其他问题,但我正在寻找在单个语句中表达这一点的最佳方式(试图了解如何更好地使用语法)。

【问题讨论】:

标签: haskell fizzbuzz


【解决方案1】:

怎么样……

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

【讨论】:

    【解决方案2】:

    与 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      = ""
    

    【讨论】:

    • 这基本上就是我刚刚所做的:[ (x, "Fizz" `ifDivisibleBy` 3 ++ "Buzz" `ifDivisibleBy` 5) | x &lt;- [1..100], let ifDivisibleBy s n = if x `mod` n == 0 then s else "" ]
    【解决方案3】:

    如果你坚持单线:

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

    【讨论】:

    • 这似乎非常接近我的想法。有什么方法可以将其归结为不需要 concat 吗?从逻辑上看,concat 对我来说是一种行为噪音。它的内容是:创建一个从 1 到 100 步的数组,其中每个元素与两个包含单个字符串元素的数组相连接(..etc)。
    • 顺便说一下,Haskell 中的列表是单链表,而不是数组;与其他语言相比,数组(例如 arrayvector 包中的数组)相对较少使用。
    • 将此标记为答案,因为它作为 1-liner 语句读取最佳,而没有复合语句,如“where”。我也喜欢表达式完全构建在列表定义中,从而赋予它更多语义上下文。
    • 你可以用join代替concat
    • 如果要去掉concat,将对应的表达式替换为:[f | f &lt;- "fizz", mod x 3 == 0] ++ [b | b &lt;- "buzz", mod x 5 == 0]。 hammar 对列表理解的滥用现在更加严重。
    【解决方案4】:

    忍不住朝另一个方向走,让它变得更复杂。看,没有mod...

    merge as@(a@(ia,sa):as') bs@(b@(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")]
    

    【讨论】:

      【解决方案5】:

      我认为你觉得你在与语法作斗争的原因是因为你混合了太多的类型。

      而不是尝试打印:

      [(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 转换为 String,请使用:

      show x
      

      【讨论】:

        【解决方案6】:

        我们不需要臭屁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"]
        

        【讨论】:

          【解决方案7】:

          Writer monad 可能看起来不错(如果你不喜欢 concat):

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

          虽然不是特别简洁。

          【讨论】:

            【解决方案8】:

            只是为了学习

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

            【讨论】:

              猜你喜欢
              • 2017-04-25
              • 1970-01-01
              • 2018-07-18
              • 2012-11-04
              • 2016-01-15
              • 2015-01-13
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              相关资源
              最近更新 更多