packages feed

tangle-0.1: examples/mono.hs

{-# LANGUAGE GeneralizedNewtypeDeriving #-}
module Main where

import Control.Monad.Trans.Reader
import Control.Monad.Trans.State
import qualified Data.Map as Map

type Key = String
type Container = Map.Map Key

newtype Tangle b a = Tangle { unTangle :: ReaderT (Container (Tangle b b)) (State (Container b)) a }
  deriving (Functor, Applicative, Monad)

hitch :: Key -> Tangle b b
hitch key = Tangle $ ReaderT $ \env -> state $ \cache -> case Map.lookup key cache of
  -- If the requested key exists in the cache, just return the value
  Just a -> (a, cache)
  Nothing -> case Map.lookup key env of
    Nothing -> error "Not found"
    Just m ->
      -- Compute the result
      let (result, cache') = unTangle m `runReaderT` env `runState` cache
      -- Insert the result to the cache
      in (result, Map.insert key result cache')

evalTangle :: Tangle b a -> Container (Tangle b b) -> a
evalTangle m env = unTangle m `runReaderT` env `evalState` Map.empty

tangles :: Container (Tangle Int Int)
tangles = Map.fromList
  [ ("foo", pure 6)
  , ("bar", pure 7)
  , ("baz", (*) <$> hitch "foo" <*> hitch "bar")
  ]

main :: IO ()
main = print $ evalTangle (hitch "baz") tangles