{-# LANGUAGE RankNTypes,
             FlexibleInstances
  #-}

-- | 
-- Module      : Control.Monad.Sharing
-- Copyright   : Chung-chieh Shan, Oleg Kiselyov, and Sebastian Fischer
-- License     : PublicDomain
-- Maintainer  : Sebastian Fischer <mailto:sebf@informatik.uni-kiel.de>
-- Stability   : experimental
-- 
-- This library provides an interface to monads that support explicit
-- sharing. A project website with tutorials can be found at
-- <http://sebfisch.github.com/explicit-sharing>.
module Control.Monad.Sharing (

  module Control.Monad,

  -- * Classes

  Sharing(..), Shareable(..), Convertible(..),

  -- * Observation functions

  collect, hasResult, results, resultDist,

  resultList, unsafeResults

 ) where

import Control.Monad
import Control.Monad.Sharing.Classes
import Control.Monad.Sharing.Implementation.CPS

import qualified Data.Set as Set
import qualified Data.Map as Map

hasResult :: (forall s . Sharing s => s a) -> Bool
hasResult a = collect (liftM (const True) a)

results :: Ord a => (forall s . Sharing s => s a) -> Set.Set a
results a = collect (liftM Set.singleton a)

resultDist :: Ord a => (forall s . Sharing s => s a) -> Map.Map a Rational
resultDist a = collect (liftM (`Map.singleton`1) a)

newtype UnsafeResults a = Unsafe { unsafe :: [a] }

instance Nondet (UnsafeResults a) where
  failure = Unsafe []

  -- does not satisfy required laws
  a ? b = Unsafe (unsafe a ++ unsafe b)

unsafeResults :: (forall s . Sharing s => s a) -> [a]
unsafeResults a = unsafe (collect (liftM (Unsafe . (:[])) a))

resultList :: (forall s . Sharing s => s a) -> IO [a]
resultList a = return (unsafeResults a)