{-# LANGUAGE CPP , DataKinds , OverloadedStrings , FlexibleContexts , GADTs , RankNTypes #-} {-# OPTIONS_GHC -Wall -fwarn-tabs #-} module Language.Hakaru.Repl where import Language.Hakaru.Types.Sing import Language.Hakaru.Syntax.ABT import qualified Language.Hakaru.Syntax.AST as T import Language.Hakaru.Syntax.AST.Transforms import Language.Hakaru.Syntax.Variable () import qualified Language.Hakaru.Parser.AST as U import Language.Hakaru.Parser.Parser (parseHakaru, parseReplLine) import Language.Hakaru.Parser.SymbolResolve (resolveAST) import Language.Hakaru.Pretty.Concrete import Language.Hakaru.Syntax.TypeCheck import Language.Hakaru.Sample import Language.Hakaru.Syntax.Value import Control.Monad.State.Strict (StateT, evalStateT, get, modify) import Control.Monad.IO.Class import Data.List (intercalate) import qualified Data.Text as Text import qualified Data.Text.IO as IO import qualified Data.Vector as V import Text.PrettyPrint (renderStyle, style, mode, Mode(LeftMode)) import qualified System.Random.MWC as MWC import System.Console.Repline type Binding = (U.AST' Text.Text -> U.AST' Text.Text) type ReplM = HaskelineT (StateT Binding IO) initialReplState :: Binding initialReplState = id extendBindings :: Binding -> Binding -> Binding extendBindings = flip (.) triv :: TrivialABT T.Term '[] a -> TrivialABT T.Term '[] a triv = id app1 :: a -> U.AST' a -> U.AST' a app1 s x = U.Var s `U.App` x resolveAndInfer :: U.AST' Text.Text -> Either Text.Text (TypedAST (TrivialABT T.Term)) resolveAndInfer x = resolveAndInferWithMode x LaxMode resolveAndInferWithMode :: ABT T.Term abt => U.AST' Text.Text -> TypeCheckMode -> Either Text.Text (TypedAST abt) resolveAndInferWithMode x mode' = let m = inferType (resolveAST x) in runTCM m Nothing mode' splitLines :: Text.Text -> Maybe (V.Vector Text.Text) splitLines = Just . V.fromList . Text.lines whenE :: MonadIO m => Either Text.Text b -> m () -> m () whenE (Left err) _ = liftIO $ IO.putStrLn err whenE (Right _) m = m illustrate :: Sing a -> MWC.GenIO -> Value a -> IO () illustrate (SMeasure s) g (VMeasure m) = do x <- m (VProb 1) g case x of Just (samp, _) -> illustrate s g samp Nothing -> illustrate (SMeasure s) g (VMeasure m) illustrate _ _ x = renderLn x renderLn :: Value a -> IO () renderLn = putStrLn . renderStyle style {mode = LeftMode} . prettyValue runOnce :: MWC.GenIO -> U.AST' Text.Text -> IO () runOnce g prog = case resolveAndInfer prog of Left err -> IO.putStrLn err Right (TypedAST typ ast) -> illustrate typ g (runEvaluate ast) type_ :: Cmd ReplM type_ prog = case parseHakaru (Text.pack prog) of Left err -> liftIO $ putStrLn (show err) Right e -> do bindings <- get let prog' = bindings (app1 "dirac" e) case resolveAndInfer prog' of Left err -> liftIO $ IO.putStrLn err Right (TypedAST (SMeasure typ) _) -> liftIO $ putStrLn (prettyTypeS typ) _ -> liftIO $ putStrLn "the impossible happened" initM :: ReplM () initM = liftIO $ putStrLn introBanner -- Evaluation -- No Typechecking of bindings cmd :: MWC.GenIO -> String -> ReplM () cmd g x = case parseReplLine (Text.pack x) of Left err -> liftIO $ putStrLn (show err) Right (Left b) -> modify (extendBindings b) Right (Right e) -> do bindings <- get let prog' = bindings (app1 "dirac" e) liftIO $ runOnce g prog' -- Typecheck bindings before adding them cmd2 :: MWC.GenIO -> Cmd ReplM cmd2 g x = case parseReplLine (Text.pack x) of Left err -> liftIO $ putStrLn (show err) Right e -> do bindings <- get case e of Left b -> let prog = bindings . b $ (app1 "dirac" U.Unit) in whenE (resolveAndInfer prog) (modify $ extendBindings b) Right e' -> let prog = bindings (app1 "dirac" e') in liftIO $ runOnce g prog repl :: MWC.GenIO -> IO () repl g = flip evalStateT initialReplState $ evalReplOpts $ ReplOpts { banner = const (pure ">>> ") , command = cmd2 g , options = opts , prefix = Just ':' , multilineCommand = Nothing , tabComplete = (Word comp) , initialiser = initM , finaliser = return Exit } -- Completion comp :: Monad m => WordCompleter m comp = listWordCompleter [":help", ":expand", ":hist", ":type"] -- Commands help :: Cmd ReplM help _ = liftIO $ putStrLn "Help!" expand :: Cmd ReplM expand prog = case parseReplLine (Text.pack prog) of Left err -> liftIO $ putStrLn (show err) Right (Left b) -> modify (extendBindings b) Right (Right e) -> do bindings <- get let prog' = bindings e case resolveAndInfer prog' of Left err -> liftIO $ IO.putStrLn err Right (TypedAST _ ast) -> liftIO $ print (pretty (expandTransformations ast)) hist :: Cmd ReplM hist = undefined opts :: Options ReplM opts = [ ("help", help), ("expand", expand), ("hist", hist), ("type", type_) ] introBanner :: String introBanner = unlines [" __ __ __", " / / / /___ _/ /______ ________ __", " / /_/ / __ `/ //_/ __ `/ ___/ / / /", " / __ / /_/ / ,< / /_/ / / / /_/ /", "/_/ /_/\\__,_/_/|_|\\__,_/_/ \\__,_/" ] main :: IO () main = MWC.createSystemRandom >>= repl