{-# LANGUAGE ConstraintKinds #-}

module Language.Explorer.Basic
    ( Explorer
    , mkExplorer
    , mkExplorerNoSharing
    , execute
    , executeAll
    , revert
    , ExplorerM.toTree
    , config
    , currRef
    , Ref
    , deref
    , leaves
    , getTrace
    , getTraces
    , getPathsFromTo
    , getPathFromTo
    , executionGraph
    , fromExport
    , toExport
    ) where

import qualified Language.Explorer.Monadic as ExplorerM
import Control.Monad.Identity

import qualified Data.IntMap as IntMap
import Data.List
import Data.Functor
import Data.Foldable
import Data.Monoid ()
import Data.Graph.Inductive.Graph (emap)

-- We shadow instead of exporting directly to make the user interaction
-- the same.
type Ref = ExplorerM.Ref
type Explorer a b = ExplorerM.Explorer a Identity b ()
type BasicLanguage p c = Eq p

mkExplorer :: BasicLanguage p c => Bool -> (c -> c -> Bool) -> (p -> c -> Maybe c) -> c -> Explorer p c
mkExplorer :: forall p c.
BasicLanguage p c =>
Bool
-> (c -> c -> Bool) -> (p -> c -> Maybe c) -> c -> Explorer p c
mkExplorer Bool
shadow c -> c -> Bool
eqfunc p -> c -> Maybe c
definterp c
initialConf = forall p (m :: * -> *) c o.
Language p m c o =>
Bool
-> (c -> c -> Bool)
-> (p -> c -> m (Maybe c, o))
-> c
-> Explorer p m c o
ExplorerM.mkExplorer Bool
shadow c -> c -> Bool
eqfunc (forall (m :: * -> *) a b.
Monad m =>
(a -> b -> Maybe b) -> a -> b -> m (Maybe b, ())
wrap p -> c -> Maybe c
definterp) c
initialConf

mkExplorerNoSharing :: BasicLanguage p c => (p -> c -> Maybe c) -> c -> Explorer p c
mkExplorerNoSharing :: forall p c.
BasicLanguage p c =>
(p -> c -> Maybe c) -> c -> Explorer p c
mkExplorerNoSharing = forall p c.
BasicLanguage p c =>
Bool
-> (c -> c -> Bool) -> (p -> c -> Maybe c) -> c -> Explorer p c
mkExplorer Bool
False (forall a b. a -> b -> a
const forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ Bool
False)

currRef :: Explorer a b -> Ref
currRef :: forall a b. Explorer a b -> Ref
currRef = forall programs (m :: * -> *) configs output.
Explorer programs m configs output -> Ref
ExplorerM.currRef

config :: Explorer a b -> b
config :: forall a b. Explorer a b -> b
config = forall programs (m :: * -> *) configs output.
Explorer programs m configs output -> configs
ExplorerM.config

deref :: Explorer p c -> Ref -> Maybe c
deref :: forall p c. Explorer p c -> Ref -> Maybe c
deref = forall p (m :: * -> *) c o. Explorer p m c o -> Ref -> Maybe c
ExplorerM.deref

-- This should be able with func composition.
wrap :: Monad m => (a -> b -> Maybe b) -> a -> b -> m (Maybe b, ())
wrap :: forall (m :: * -> *) a b.
Monad m =>
(a -> b -> Maybe b) -> a -> b -> m (Maybe b, ())
wrap a -> b -> Maybe b
def a
p b
e = forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ (a -> b -> Maybe b
def a
p b
e, ())

execute :: BasicLanguage p c => p -> Explorer p c -> Explorer p c
execute :: forall p c. BasicLanguage p c => p -> Explorer p c -> Explorer p c
execute p
p Explorer p c
e = forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Language p m c o =>
p -> Explorer p m c o -> m (Explorer p m c o, o)
ExplorerM.execute p
p Explorer p c
e

executeAll :: BasicLanguage p c => [p] -> Explorer p c -> Explorer p c
executeAll :: forall p c.
BasicLanguage p c =>
[p] -> Explorer p c -> Explorer p c
executeAll [p]
p Explorer p c
e = forall a b. (a, b) -> a
fst forall a b. (a -> b) -> a -> b
$ forall a. Identity a -> a
runIdentity forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Language p m c o =>
[p] -> Explorer p m c o -> m (Explorer p m c o, o)
ExplorerM.executeAll [p]
p Explorer p c
e

revert :: ExplorerM.Ref -> Explorer p c -> Maybe (Explorer p c)
revert :: forall p c. Ref -> Explorer p c -> Maybe (Explorer p c)
revert = forall p (m :: * -> *) c o.
Ref -> Explorer p m c o -> Maybe (Explorer p m c o)
ExplorerM.revert

removeOutput :: ((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput :: forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput ((Ref, c)
s, (p
p, o
_), (Ref, c)
t) = ((Ref, c)
s, p
p, (Ref, c)
t)

incomingEdges :: Ref -> Explorer p c -> [((Ref, c), p, (Ref, c))]
incomingEdges :: forall p c. Ref -> Explorer p c -> [((Ref, c), p, (Ref, c))]
incomingEdges Ref
r Explorer p c
e = forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Ref -> Explorer p m c o -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.incomingEdges Ref
r Explorer p c
e

getTrace :: Explorer p c -> [((Ref, c), p, (Ref, c))]
getTrace :: forall p c. Explorer p c -> [((Ref, c), p, (Ref, c))]
getTrace Explorer p c
e = forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Explorer p m c o -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.getTrace Explorer p c
e

getTraces :: Explorer p c -> [[((Ref, c), p, (Ref, c))]]
getTraces :: forall p c. Explorer p c -> [[((Ref, c), p, (Ref, c))]]
getTraces Explorer p c
e = forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput) forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Explorer p m c o -> [[((Ref, c), (p, o), (Ref, c))]]
ExplorerM.getTraces Explorer p c
e

getPathsFromTo :: Explorer p c -> Ref -> Ref -> [[((Ref, c), p, (Ref, c))]]
getPathsFromTo :: forall p c.
Explorer p c -> Ref -> Ref -> [[((Ref, c), p, (Ref, c))]]
getPathsFromTo Explorer p c
e Ref
s Ref
t = forall a b. (a -> b) -> [a] -> [b]
map (forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput) forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Explorer p m c o -> Ref -> Ref -> [[((Ref, c), (p, o), (Ref, c))]]
ExplorerM.getPathsFromTo Explorer p c
e Ref
s Ref
t

getPathFromTo :: Explorer p c -> Ref -> Ref -> [((Ref, c), p, (Ref, c))]
getPathFromTo :: forall p c. Explorer p c -> Ref -> Ref -> [((Ref, c), p, (Ref, c))]
getPathFromTo Explorer p c
e Ref
s Ref
t = forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput forall a b. (a -> b) -> a -> b
$ forall p (m :: * -> *) c o.
Explorer p m c o -> Ref -> Ref -> [((Ref, c), (p, o), (Ref, c))]
ExplorerM.getPathFromTo Explorer p c
e Ref
s Ref
t

executionGraph :: Explorer p c -> ((Ref, c), [(Ref, c)], [((Ref, c), p, (Ref, c))])
executionGraph :: forall p c.
Explorer p c -> ((Ref, c), [(Ref, c)], [((Ref, c), p, (Ref, c))])
executionGraph Explorer p c
e = ((Ref, c)
curr, [(Ref, c)]
nodes, forall a b. (a -> b) -> [a] -> [b]
map forall c p o.
((Ref, c), (p, o), (Ref, c)) -> ((Ref, c), p, (Ref, c))
removeOutput [((Ref, c), (p, ()), (Ref, c))]
graph)
  where
    ((Ref, c)
curr, [(Ref, c)]
nodes, [((Ref, c), (p, ()), (Ref, c))]
graph) = forall p (m :: * -> *) c o.
Explorer p m c o
-> ((Ref, c), [(Ref, c)], [((Ref, c), (p, o), (Ref, c))])
ExplorerM.executionGraph Explorer p c
e

leaves :: Explorer p c -> [(Ref, c)]
leaves :: forall p c. Explorer p c -> [(Ref, c)]
leaves = forall p (m :: * -> *) c o. Explorer p m c o -> [(Ref, c)]
ExplorerM.leaves

toExport :: Explorer p c -> (Ref, [(Ref, c)], [(Ref, Ref, p)])
toExport :: forall p c. Explorer p c -> (Ref, [(Ref, c)], [(Ref, Ref, p)])
toExport = forall {a} {b} {a} {b} {c} {b}.
(a, b, [(a, b, (c, b))]) -> (a, b, [(a, b, c)])
removeOut forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall p (m :: * -> *) c o.
Explorer p m c o -> (Ref, [(Ref, c)], [(Ref, Ref, (p, o))])
ExplorerM.toExport
  where
    removeOut :: (a, b, [(a, b, (c, b))]) -> (a, b, [(a, b, c)])
removeOut (a
c, b
nodes, [(a, b, (c, b))]
edges) = (a
c, b
nodes, forall a b. (a -> b) -> [a] -> [b]
map (\(a
s, b
t, (c
p, b
_)) -> (a
s, b
t, c
p)) [(a, b, (c, b))]
edges)

fromExport :: Explorer p c -> (Ref, [(Ref, c)], [(Ref, Ref, p)]) -> Explorer p c
fromExport :: forall p c.
Explorer p c -> (Ref, [(Ref, c)], [(Ref, Ref, p)]) -> Explorer p c
fromExport Explorer p c
e (Ref, [(Ref, c)], [(Ref, Ref, p)])
exported = forall p (m :: * -> *) c o.
Explorer p m c o
-> (Ref, [(Ref, c)], [(Ref, Ref, (p, o))]) -> Explorer p m c o
ExplorerM.fromExport Explorer p c
e (forall {a} {b} {a} {b} {a}.
(a, b, [(a, b, a)]) -> (a, b, [(a, b, (a, ()))])
addOut (Ref, [(Ref, c)], [(Ref, Ref, p)])
exported)
  where
    addOut :: (a, b, [(a, b, a)]) -> (a, b, [(a, b, (a, ()))])
addOut (a
c, b
nodes, [(a, b, a)]
edges) = (a
c, b
nodes, forall a b. (a -> b) -> [a] -> [b]
map (\(a
s, b
t, a
p) -> (a
s, b
t, (a
p, ()))) [(a, b, a)]
edges)