{-|

Module      : MySum
Description : A module to compute the sum of a list of numbers.
Copyright   : © Frank Jung, 2025
License     : GPL-3

This is a simple example of using the 'ST' Monad for stateful summation of a
list.

The 'ST' monad in Haskell allows you to perform mutable (stateful) computations
in a safe, local way. It stands for "State Thread" and is defined in
Control.Monad.ST ('ST').

== Key Points

[Local Mutability] You can create and modify mutable variables ('STRef's)
  inside the 'ST' monad.
[Safety] Changes made in the 'ST' monad are not visible outside; the
  mutation is encapsulated.
[Pure Interface] When you run an 'ST' computation (using 'runST'), you get a
  pure result, and the mutable state cannot escape.

== Example usage

Computes the sum of a list using the 'mySum' function:

@
let total = mySum [1, 2, 3, 4, 5]
@

-}

module MySum (
    mySum
) where

import           Control.Monad.ST
import           Data.STRef

-- | Computes the sum of a list of integers using the ST monad.
sumSt ::
    [Int]                     -- ^ The list of integers to sum
    -> STRef s Int            -- ^ A mutable reference to accumulate the sum
    -> ST s Int               -- ^ The stateful computation that returns the sum
sumSt :: forall s. [Int] -> STRef s Int -> ST s Int
sumSt []     STRef s Int
_ = Int -> ST s Int
forall a. a -> ST s a
forall (m :: * -> *) a. Monad m => a -> m a
return Int
0           -- Base case: empty list returns 0
sumSt (Int
x:[Int]
xs) STRef s Int
accumRef = do
    Int
accum <- STRef s Int -> ST s Int
forall s a. STRef s a -> ST s a
readSTRef STRef s Int
accumRef     -- Read the current value of the accumulator
    STRef s Int -> Int -> ST s ()
forall s a. STRef s a -> a -> ST s ()
writeSTRef STRef s Int
accumRef (Int
accum Int -> Int -> Int
forall a. Num a => a -> a -> a
+ Int
x) -- Update the accumulator with the new value
    [Int] -> STRef s Int -> ST s Int
forall s. [Int] -> STRef s Int -> ST s Int
sumSt [Int]
xs STRef s Int
accumRef               -- Recursively for the remaining elements

-- | Computes the sum of a list of integers in a stateful manner.
mySum :: [Int] -> Int
mySum :: [Int] -> Int
mySum [Int]
xs = (forall s. ST s Int) -> Int
forall a. (forall s. ST s a) -> a
runST ((forall s. ST s Int) -> Int) -> (forall s. ST s Int) -> Int
forall a b. (a -> b) -> a -> b
$ do
    STRef s Int
accumRef <- Int -> ST s (STRef s Int)
forall a s. a -> ST s (STRef s a)
newSTRef Int
0    -- Create a new STRef to hold the accumulator
    Int
_ <- [Int] -> STRef s Int -> ST s Int
forall s. [Int] -> STRef s Int -> ST s Int
sumSt [Int]
xs STRef s Int
accumRef    -- Compute the sum using the ST monad
    STRef s Int -> ST s Int
forall s a. STRef s a -> ST s a
readSTRef STRef s Int
accumRef        -- Read the final sum from the STRef