import Data.List (unfoldr, mapAccumR)
import Data.Ratio ((%), denominator, numerator)
import Text.Printf (PrintfArg, printf)


farey :: Integer -> [Rational]
farey n = 0: unfoldr step (0, 1, 1, n)
  where
    step (a, b, c, d)
      | c > n = Nothing
      | otherwise =
        let k = (n + b) `quot` d
        in Just (c %d, (c, d, k * c - a, k * d - b))





fareys :: ([Rational] -> a) -> [Integer] -> [(Integer, a)]
fareys fn ns = snd $ mapAccumR prune (farey $ last ns) ns
  where
    prune rs n =
      let rs'' = filter ((<= n) . denominator) rs
      in (rs'', (n, fn rs''))

fprint
  :: (PrintfArg b)
  => String -> [(Integer, b)] -> IO ()
fprint fmt = mapM_ (uncurry $ printf fmt)

showFracs :: [Rational] -> String
showFracs =
  unwords .
  map (concat . (<*>) [show . numerator, const "/", show . denominator] . pure)

main :: IO ()
main = do
  putStrLn "Farey Sequences\n"
  fprint "%2d%s\n" $ fareys showFracs [1 .. 11]
  putStrLn "\nSequence Lengths\n"
  fprint "%4d%d\n" $ fareys length [100,200 .. 1000]