{"action":"created","issue":{"url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/2","labels_url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/2/labels{/name}","comments_url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/2/comments","events_url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/2/events","html_url":"https://github.com/CNMDR3G/CNMDR3G/issues/2","id":60194535,"number":2,"title":"FizzBuzz: 分享一个解法","user":{"login":"Javran","id":1096354,"avatar_url":"https://avatars.githubusercontent.com/u/1096354?v=3","gravatar_id":"","url":"https://api.github.com/users/Javran","html_url":"https://github.com/Javran","followers_url":"https://api.github.com/users/Javran/followers","following_url":"https://api.github.com/users/Javran/following{/other_user}","gists_url":"https://api.github.com/users/Javran/gists{/gist_id}","starred_url":"https://api.github.com/users/Javran/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/Javran/subscriptions","organizations_url":"https://api.github.com/users/Javran/orgs","repos_url":"https://api.github.com/users/Javran/repos","events_url":"https://api.github.com/users/Javran/events{/privacy}","received_events_url":"https://api.github.com/users/Javran/received_events","type":"User","site_admin":false},"labels":[],"state":"open","locked":false,"assignee":null,"milestone":null,"comments":8,"created_at":"2015-03-07T06:48:30Z","updated_at":"2015-03-13T08:57:59Z","closed_at":null,"body":"一开始叫我读FizzBuzz我是拒绝的,因为你不能叫我读我就读,首先我要试一下\r\n\r\n所以暂时没读多少的情况下,先琢磨出了个解法.抛砖引玉吧.\r\n\r\n这个题看起来像MonadPlus能干的事情,不过事实上不是...\r\n\r\n因为MonadPlus中一旦有一个地方计算失败了,后续的计算都被取消了.\r\n\r\n所以我对MonadPlus做了一点\"hack\", 以下代码的关键在于`amend`和`unamend`.\r\n\r\n`amend oops m` 的意思是,如果`m`失败了,那么就加个特技`oops`上去,好让后面的计算能接着跑\r\n\r\n`unamend oops (amend oops m) = m`, 换句话说`unamend oops`取消了`amend oops`的效果.\r\n\r\n`oops` 需要取一个在计算成功的情况下不可能得到的值,这样`unamend`才能正确把这个值从结果里移除. 所以这个地方直接让`oops = []`.\r\n\r\n```haskell\r\nmodule FizzBuzz where\r\n\r\nimport Prelude hiding (mapM_,concat,product)\r\nimport Control.Monad hiding (mapM_)\r\nimport Data.Foldable\r\n\r\nkeepInput :: (a -> b) -> a -> (b,a)\r\nkeepInput f x = (f x, x)\r\n\r\nfizzbuzz :: Int -> String\r\nfizzbuzz n = head $ amend (show n) divisible\r\n  where\r\n    -- invariant: length (amend _ _) /= 0\r\n    amend oops m = m `mplus` [ oops ]\r\n    unamend oops = filter (/= oops)\r\n    fb = concat (foldMap (amend [])\r\n                         [ [\"fizz\" | test  3]\r\n                         , [\"buzz\" | test  5]\r\n                         , [\"hiss\" | test  7]\r\n                         , [\"howl\" | test 11]\r\n                         ])\r\n    divisible = unamend [] (return fb)\r\n    test x = n `mod` x == 0\r\n\r\nmain :: IO ()\r\nmain = mapM_ (print . keepInput fizzbuzz)\r\n             [1.. product [3,5,7,11]]\r\n```\r\n\r\n欢迎各种吐槽!"},"comment":{"url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/comments/78875053","html_url":"https://github.com/CNMDR3G/CNMDR3G/issues/2#issuecomment-78875053","issue_url":"https://api.github.com/repos/CNMDR3G/CNMDR3G/issues/2","id":78875053,"user":{"login":"ninegua","id":1549364,"avatar_url":"https://avatars.githubusercontent.com/u/1549364?v=3","gravatar_id":"","url":"https://api.github.com/users/ninegua","html_url":"https://github.com/ninegua","followers_url":"https://api.github.com/users/ninegua/followers","following_url":"https://api.github.com/users/ninegua/following{/other_user}","gists_url":"https://api.github.com/users/ninegua/gists{/gist_id}","starred_url":"https://api.github.com/users/ninegua/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ninegua/subscriptions","organizations_url":"https://api.github.com/users/ninegua/orgs","repos_url":"https://api.github.com/users/ninegua/repos","events_url":"https://api.github.com/users/ninegua/events{/privacy}","received_events_url":"https://api.github.com/users/ninegua/received_events","type":"User","site_admin":false},"created_at":"2015-03-13T08:57:59Z","updated_at":"2015-03-13T08:57:59Z","body":"的确是个 semigroup，有一边的 identity，但基础结构不是 product，而是 sum\r\n\r\n```haskell\r\nLeft l *++ Left r  = Left $ l ++ r\r\nx      *++ Right _ = x\r\n_      *++ x       = x\r\n\r\ntoFB i = foldr1 (*++) [base i, fizz i, buzz i] \r\n  where \r\n    test n i | i `mod` n == 0 = Left \r\n             | otherwise      = Right\r\n    base = Right . show \r\n    fizz = flip (test 3) \"fizz\"\r\n    buzz = flip (test 5) \"buzz\"\r\n\r\nshowFB = either id id \r\n\r\nfizbuzz = map (showFB . toFB)\r\n```"}}