-- Jonathan Frech, 2022-02-18, 2022-03-18, 2022-03-19
-- See `https://blog.jfrech.com/256/`.


type Action = [Int] -> ([Int],[Int])

flat :: Int -> Action
flat k xs = (take k xs, drop k xs)

grab :: (Int,Int) -> Action
grab (j,k) xs = (take k (drop j xs), take j xs ++ drop (j+k) xs)

eval :: [Action] -> [Int] -> [Int]
eval (a:as) xs = fst (a xs) ++ eval as (snd $ a xs)

tcheFlat :: Int -> [Int]
tcheFlat 1 = [1..]
tcheFlat n = eval (cycle actions) $ tcheFlat (n-1) where
    actions = concat [[flat (n-m), grab (n-m-1,m)] | m <- [1..n-1]]


chunksOf :: Int -> [a] -> [[a]]
chunksOf n xs = take n xs : chunksOf n (drop n xs)

infixl 9 ##
(##) :: [a] -> Int -> a
xs ## k = xs !! (k-1)

tche n i j | j <= n    = (chunksOf n $ tcheFlat n) ## i ## j
           | otherwise = -n


discreteLimit :: (Int -> Int) -> Int
discreteLimit f = converge $ map f [1..] where
    converge (x:x':xs) | x == x'   = x
                       | otherwise = converge (x':xs)

tcheInf i j = discreteLimit $ \n -> tche n i j
