External Publication
Visit Post

Minimal processing of continued fractions

Haskell Community [Unofficial] February 15, 2026
Source

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

Loading comments...