HaskellでZipListを使ったFizzBuzz

{-# LANGUAGE TypeApplications #-}

{-# OPTIONS_GHC -Wall -fno-warn-tabs #-}

module Main (main) where

import Control.Applicative

import Data.Foldable

z :: [a] -> ZipList a; unz :: ZipList a -> [a]; cycleZ :: [a] -> ZipList a

(z, unz, cycleZ) = (ZipList, getZipList, z . cycle)

main :: IO ()

main = traverse_ (either @Int print putStrLn) . take 100 . unz $ z [1 ..]

<**> cycleZ [Left, Left, const $ Right "Fizz"]

<**> cycleZ [id, id, id, id,

either (const Right) ((Right .) . (<>)) `flip` "Buzz"]

https://github.com/YoshikuniJujo/test_haskell/blob/master/tribial/tribial-mains/app/fizzbuzz-ziplist.hs

Reply to this note

Please Login to reply.

Discussion

考えかたとしては

* 1から始まる無限リストと

* 先頭の要素を1番目としたときに3の倍数番目の要素が「引数を無視して"Fizz"を返す関数」であるようなリストと

* 同様に5の倍数番目の要素が「引数が数値なら"Buzz"を、文字列ならそれに"Buzz"を追加した文字列を返す関数」であるようなリスト

の3つのリストを用意して、それを組み合わせてFizzBuzzの結果を意味する無限リストを生成し、そこから先頭の100要素を取り出して、順に表示する。

という話。

` ` `

let (m ~> str) x = str <$ guard (x ` mod` m == 0)

in map (fromMaybe . show <*> 3 ~> "fizz" <> 5 ~> "buzz")

` ` `