Minimal processing of continued fractions
Haskell Community [Unofficial]
February 15, 2026
I see it as a stateful fold with a stateful unfold inside it:
{-# LANGUAGE LambdaCase #-}
import Control.Monad.State.Lazy
import Data.Foldable
import Control.Monad
type Mat = (Integer, Integer, Integer, Integer)
matmul (a1, b1, c1, d1) (a2, b2, c2, d2) = (a1*a2 + b1*c2,
a1*b2 + b1*d2,
c1*a2 + d1*c2,
c1*b2 + d1*d2)
unfoldM :: Monad m => m (Maybe a) -> m [a]
unfoldM m = m >>= \case
Nothing -> pure []
Just x -> (x :) <$> unfoldM m
cf_to_decimal :: [Integer] -> [Integer]
cf_to_decimal cf = evalState (foldr feed end cf) (1,0,0,1) where
emit :: State Mat (Maybe Integer)
emit = do
m@(a,b,c,d) <- get
let y0 = a `div` c
y1 = b `div` d
if c /= 0 && d /= 0 && y0 == y1 then do
put (matmul (10, -10*y0, 0, 1) m)
pure (Just y0)
else pure Nothing
feed :: Integer -> State Mat [Integer] -> State Mat [Integer]
feed x rest = do
modify (\m -> matmul m (x,1,1,0))
(<>) <$> unfoldM emit <*> rest
end :: State Mat [Integer]
end = do
modify (\(a,b,c,d) -> (a,a,c,c))
unfoldM $ do
(a,_,_,_) <- get
if a == 0 then pure Nothing else emit
This also gives you the laziness you want if you use the lazy state monad.
Discussion in the ATmosphere