clplug-0.1.0.0: examples/routes/Search.hs
{-# LANGUAGE
LambdaCase,
DuplicateRecordFields,
TypeSynonymInstances,
FlexibleInstances
#-}
module Search (
Search
, Way
, evalTo
, evalRefs
, evalChans
, results'
, results
, search
, hydrate
, increment
, chop
, getNodeInt
)where
import Numeric
import Data.Char
import System.IO
import Data.Lightning
import Data.Graph.Inductive.Graph
import Data.Graph.Inductive.PatriciaTree
import Control.Monad.Reader
import Control.Monad.State
import Control.Concurrent
import Control.Concurrent.Chan
import qualified Data.Sequence as Q
import Data.Sequence (Seq(..),(<|),(|>),(><))
import Data.Foldable
import Route
type Search b = Reader (Gr () b, Node, Node) -- from / to
type Way b = Q.Seq b
type Ref = Q.Seq Int
type Deref b = (Ref, Way b)
type Eebe b = Either (Deref b) (Way b)
evalTo :: Channel b => Gr () b -> Node -> Node -> Int -> [Ref]
evalTo = evalBy resLength
evalChans :: Channel b => Gr () b -> Node -> Node -> Int -> [Way b]
evalChans = evalBy results'
evalRefs :: Channel b => Gr () b -> Node -> Node -> Int -> [Ref]
evalRefs = evalBy results
evalBy s g n m l = (`runReader` (g, n, m)) . (`evalStateT` (Empty, [])) $ s l
results' :: Channel b => Int -> StateT (Ref, [Way b]) (Search b) [Way b]
results' x = do
(r , c) <- get
(w, r') <- lift $ search r
put (increment.chop $ r', w : c)
if x > length c
then results' x
else return c
results :: Channel b => Int -> StateT (Ref, [Ref]) (Search b) [Ref]
results x = do
(r , c) <- get
(_, r') <- lift $ search r
put (increment.chop $ r', r' : c)
if x > length c
then results x
else return c
resLength :: Channel b => Int -> StateT (Ref, [Ref]) (Search b) [Ref]
resLength j = do
(r, c) <- get
(_, r') <- lift $ search r
put (increment.chop $ r', r':c)
if j >= length r'
then resLength j
else return c
search :: Channel b => Ref -> Search b (Way b, Ref)
search r = (hydrate r) >>= \case
(Left x) -> do
search $ nextr r x
(Right y) -> do
(fin (r, y) ) >>= \case
Nothing -> search $ increment r
(Just z) -> lift $ pure z
fin :: Channel b => (Ref, Way b) -> Search b (Maybe (Way b, Ref))
fin (r, w) = do
(g, n, v) <- ask
oo <- outgoing w
let {
f = dropWhile (not.(== v).fst) oo;
lo = length oo;
la = length f ;
rr = lo - la
}
case f of
[] -> pure Nothing
(x:_) -> pure $ Just ( w |> snd x, r |> rr)
nextr :: Channel b => Ref -> Deref b -> Ref
nextr r (r', c)
| z == Q.length r = extend.increment.chop $ r
| z == 0 = extendTo (Q.length r + 1) Empty
| otherwise = extendTo (Q.length r) $ increment $ Q.take z r
where z = Q.length c
hydrate :: Channel b => Ref -> (Search b) (Eebe b)
hydrate r = evalStateT h (r, Empty)
h :: Channel b => StateT (Deref b) (Search b) (Eebe b)
h = get >>= \case
(Empty, c) -> return $ Right c
dr@(y :<| t, c) -> do
(g, n, v) <- lift ask
oo <- lift $ outgoing c
case oo !? y of
Nothing -> pure $ Left dr
Just (m, x) -> put (t, c |> x) >> h
outgoing :: Channel b => Way b -> Search b [(Node, b)]
outgoing Empty = do
(g, n, v) <- ask
pure $ lsuc g n
outgoing (c :|> d) = do
(g, n, v) <- ask
pure $ lsuc g (toNode d)
increment :: Ref -> Ref
increment Empty = Q.singleton 0
increment (r :|> x) = r |> (x + 1)
extend :: Ref -> Ref
extend r = r |> 0
chop :: Ref -> Ref
chop Empty = Empty
chop (r :|> _) = r
extendTo :: Int -> Ref -> Ref
extendTo x r
| length r >= x = r
| otherwise = extendTo x $ extend r
toNode :: Channel c => c -> Node
toNode = getNodeInt.cDest
getNodeInt s = case readHex.filter isHexDigit $ show s of
([]) -> 0
(x:_)-> fst x
(!?) :: (Foldable t, Eq b, Num b) => t a -> b -> Maybe a
(!?) = foldr voo (const Nothing)
where
voo :: (Eq b, Num b) => a -> (b -> Maybe a) -> b -> Maybe a
voo x r k
| k == 0 = Just x
| otherwise = r $ k-1