freer-effects-0.3.0.0: src/Control/Monad/Freer/NonDet.hs
{-# LANGUAGE DataKinds #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE NoImplicitPrelude #-}
{-# LANGUAGE TypeOperators #-}
-- |
-- Module: Control.Monad.Freer.NonDet
-- Description: Non deterministic effects
-- Copyright: 2017 Ixperta Solutions s.r.o.
-- License: BSD3
-- Maintainer: ixcom-core@ixperta.com
-- Stability: experimental
-- Portability: GHC specific language extensions.
--
-- Composable handler for 'NonDet' effects.
module Control.Monad.Freer.NonDet
( NonDet(..)
, makeChoiceA
, msplit
)
where
import Control.Applicative (Alternative, (<|>), empty, pure)
import Control.Monad (liftM2, msum, return)
import Data.Bool (Bool(False, True))
import Data.Function (($), (.))
import Data.Maybe (Maybe(Just, Nothing))
import Control.Monad.Freer.Internal
( Eff(E, Val)
, Member
, NonDet(MPlus, MZero)
, handleRelay
, prj
, qApp
, qComp
, tsingleton
)
-- | A handler for nondeterminstic effects.
makeChoiceA
:: Alternative f
=> Eff (NonDet ': effs) a
-> Eff effs (f a)
makeChoiceA = handleRelay (return . pure) $ \m k ->
case m of
MZero -> return empty
MPlus -> liftM2 (<|>) (k True) (k False)
msplit
:: Member NonDet effs
=> Eff effs a
-> Eff effs (Maybe (a, Eff effs a))
msplit = loop []
where
loop jq (Val x) = return (Just (x, msum jq))
loop jq (E u q) = case prj u of
Just MZero -> case jq of
[] -> return Nothing
(j:jq') -> loop jq' j
Just MPlus -> loop (qApp q False : jq) (qApp q True)
Nothing -> E u (tsingleton k)
where
k = qComp q (loop jq)