esotericbot-0.0.1: hs_plugins/SK.hs
{-# OPTIONS -XScopedTypeVariables #-}
import Text.ParserCombinators.Parsec
import System.Environment
import Data.List
import Data.Maybe
import Data.Graph.Inductive
import qualified Data.Foldable as F
import Control.Monad.State
import Control.Arrow
data SK =
App
| S
| K
| I
| PH Char
deriving Eq
type SKM =
StateT SKgr IO
-- for output of results
data SKstr =
SKstr [ SKstr ]
| ASK SK
instance Show SKstr where
show ( SKstr sks ) =
"(" ++ ( concat $ map show sks ) ++ ")"
show ( ASK sk ) =
show sk
type SKgr =
Gr SK Int
instance Show SK where
show App =
"App"
show ( PH c ) =
[ c ]
show S =
"S"
show K =
"K"
show I =
"I"
sk_str = do
complex_sks <- node_to_str 0
let skstr = simplify complex_sks
return $
case skstr of
SKstr sks ->
sks
_ ->
[ skstr ]
simplify ( SKstr sks ) =
if length sks == 1
then
simplify $ head sks
else
SKstr $ map simplify sks
simplify x =
x
eval first red n can_fail = do
msk <- find_term n
maybe next
( \ ( sk , p ) -> do
input <- suck_input sk p [ ]
if length input >= suck_level sk
then do
sub first red ( snd $ head p , snd $ head $ tail p ) sk input
eval False red n False
else
next
)
msk
where
next =
if can_fail
then
sk_str
else
eval False red ( n + 1 ) True
sub first red ( n , parent ) sk input = do
oldgr <- getGr
if ( red && not first ) then sk_str >>= liftIO . output_sk_strs else return ( )
let writeNode a g = do
( x , _ ) <- valueOf a
case x of
App ->
putGr $ insEdges ( inn oldgr n ++ ( mkEdgesFrom n $ out oldgr a ) ) $ insNode ( n , x ) $ delNode n g
_ ->
putGr $ insEdges ( inn oldgr n ) $ insNode ( n , x ) $ delNode n g
case sk of
K ->
case input of
[ a , b ] -> do
writeNode a $ delNode a $ cleanupNode b oldgr
_ ->
return ( )
S -> do
case input of
[ a , b , c ] -> do
( aVal , _ ) <- valueOf a
( bVal , _ ) <- valueOf b
( cVal , _ ) <- valueOf c
cloneNode c a
gr <- getGr
let bc = [ ( b , newb , 0 ) , ( b , newc , 1 ) ]
[ newb , newc ] = newNodes 2 gr
newbEdges = mkEdgesFrom newb $ out gr b
newcEdges = mkEdgesFrom newc $ out gr c
nEdges = mkEdgesFrom n $ out oldgr a
parentEdges = [ ( parent , n , 0 ) , ( parent , a , 1 ) , ( parent , b , 2 ) ]
without_old_nodes = delNode n $ delNode c $ delNode b $ gr
new_node_gr = insNode ( b , App )
$ insNode ( newc , cVal )
$ insNode ( newb , bVal )
$ insNode ( n , aVal )
$ without_old_nodes
new_gr = insEdges parentEdges
$ insEdges newbEdges
$ insEdges newcEdges
$ insEdges nEdges
$ insEdges bc
$ new_node_gr
putGr new_gr
_ ->
return ( )
I ->
case input of
[ a ] -> do
writeNode a $ delNode a oldgr
_ ->
return ( )
where
mkEdgesFrom n es = map ( \ ( _ , to , v ) -> ( n , to , v ) ) es
cloneNode from to = do
gr <- getGr
str <- node_to_str from
putGr $ delNode to gr
add_node_str to str
add_node_str n skstr = do
gr <- getGr
case skstr of
SKstr sks -> do
putGr $ insNode ( n , App ) gr
mapM_ ( joinToNode n ) sks
ASK x ->
putGr $ insNode ( n , x ) gr
where
joinToNode n sk = do
gr <- getGr
( _ , seq ) <- valueOf n
let newEdge = if null seq
then 0
else fst ( maximum seq ) + 1
newNode = head $ newNodes 1 gr
case sk of
SKstr sks -> do
putGr $ insEdge ( n , newNode , newEdge ) $ insNode ( newNode , App ) gr
mapM_ ( joinToNode newNode ) sks
ASK x -> do
putGr $ insEdge ( n , newNode , newEdge ) $ insNode ( newNode , x ) gr
node_to_str n = do
( sk , seq ) <- valueOf n
case sk of
App -> do
linkedVals <- mapM node_to_str $ map snd seq
return $ SKstr linkedVals
_ ->
return $ ASK sk
cleanupNode n gr =
let ( Just ( _ , _ , sk , seq ) , withoutn ) = match n gr
in
case sk of
App ->
foldr cleanupNode withoutn $ map snd seq
_ ->
withoutn
sk_panic msg =
error $ unlines [ "SK panic! The possible happened!!!1"
, msg
]
valueOf a = do
gr <- getGr
maybe ( sk_panic $ "Lookup for node " ++ show a ++ " failed!" )
( \ ( _ , _ , sk , sks ) -> return ( sk , sort sks ) )
( fst $ match a gr )
suck_input sk p sucked = do
if could_suck_more sk sucked
then do
ms <- suck_one p
maybe ( return sucked )
( \ ( newp , s ) -> suck_input sk newp $ sucked ++ [ s ] )
ms
else
return sucked
suck_one ( ( Just edge_to_parent , _ ) : next@( ( _ , parent_address ) : rest ) ) = do
( _ , sequence ) <- valueOf parent_address
let mnext_edge_and_term = find ((<) edge_to_parent . fst ) sequence
maybe ( suck_one next )
( \ ( next_edge , next_term ) -> do
return $ Just ( ( Just next_edge , next_term ) : next , next_term )
)
( mnext_edge_and_term)
suck_one _ =
return Nothing
getGr :: SKM SKgr
getGr =
get
putGr :: SKgr -> SKM ( )
putGr graph = do
put graph
find_term n = do
terms <- first_terms ( Nothing , 0 ) [ ]
if length terms > n
then
return $ Just $ terms !! n
else
return Nothing
first_terms :: ( Maybe Int , Int ) -> [ ( Maybe Int , Int ) ] -> SKM [ ( SK , [ ( Maybe Int , Int ) ] ) ]
first_terms addr@( maybe_edge , n ) path = do
( sk , sequence ) <- valueOf n
skterm ( if null sequence
then
return [ ]
else do
( nVal , _ ) <- valueOf $ snd $ head sequence
skterm ( do
let tovisit = map ( first Just ) sequence
ts <- mapM ( flip first_terms ( addr : path ) ) tovisit
let just_ts = concat ts
if null just_ts
then
return [ ]
else
return just_ts
)
( const $ do
return [ ( nVal , ( first Just $ head sequence ) : addr : path ) ]
)
nVal
)
( const $
return [ ]
)
sk
skterm f g t =
case t of
App ->
f
PH c ->
f
x ->
g x
suck_level K = 2
suck_level I = 1
suck_level S = 3
sk_strP = do
sk <- noneOf ")"
case sk of
'k' -> isK
's' -> isS
'i' -> isI
'K' -> isK
'S' -> isS
'I' -> isI
'(' -> do
sks <- many sk_strP
char ')'
return $ SKstr sks
pl ->
return $ ASK $ PH pl
where
isK = return $ ASK K
isS = return $ ASK S
isI = return $ ASK I
could_suck_more sk sucked =
if length sucked >= suck_level sk
then
False
else
True
main = do
prog <- getContents
args <- getArgs
exec_sk ( not $ null args ) prog
exec_sk red skprog = do
( _ , skgr ) <- parse_sk skprog
ss <- evalStateT ( eval True red 0 False ) skgr
output_sk_strs ss
output_sk_strs :: [ SKstr] -> IO ( )
output_sk_strs sk_strs = do
putStrLn $ concat $ map show sk_strs
parse_sk sk = do
name <- getProgName
case parse ( many $ sk_strP ) name sk of
Left err ->
error $ show err
Right skstr ->
build_initial $ SKstr skstr
build_initial skstr =
flip runStateT empty $ add_node_str 0 skstr