packages feed

jupyter-0.9.0: examples/calculator/Main.hs

{-|
Module      : Main
Description : Main module for a stdin-using Jupyter kernel created using the @jupyter@ library.
Copyright   : (c) Andrew Gibiansky, 2016
License     : MIT
Maintainer  : andrew.gibiansky@gmail.com
Stability   : stable
Portability : POSIX

This module is the Main module for @kernel-calculator@, a Jupyter kernel which implements a simple
calculator language using the @jupyter@ library. It is intended to demonstrate a full yet basic kernel,
one which implements execution, inspection, completion, as well as the basic informational requests.
-}

{-# Language OverloadedStrings #-}
module Main(main) where

-- Imports from 'base'
import           Control.Concurrent (newMVar)
import           System.Environment (getArgs)
import           System.Exit (exitFailure)
import           System.IO (stderr)

-- Imports from 'text'
import qualified Data.Text.IO as T

-- Imports from 'jupyter'
import           Jupyter.Install (installKernel, simpleKernelspec, InstallUser(..), InstallResult(..),
                                  Kernelspec)
import           Jupyter.Kernel (readProfile, serve, defaultCommHandler)

-- Imports from 'kernel-calculator'
import           Calculator.Handler (requestHandler)

-- | In `main`, support two commands:
--
--    - `kernel-calculator install`: Register this kernel with Jupyter. 
--    - `kernel-calculator kernel $FILE`: Serve a kernel given ports in connection file $FILE.
main :: IO ()
main = do
  args <- getArgs
  case args of
    ["install"] -> runInstall
    ["kernel", profilePath] -> runKernel profilePath
    _ -> putStrLn $ "Invalid arguments: " ++ show args

-- | Register this kernel with Jupyter.
runInstall :: IO ()
runInstall =
  installKernel InstallLocal calculatorKernelspec >>= handleInstallResult
  where
    -- A basic kernelspec with limited info.
    calculatorKernelspec :: Kernelspec
    calculatorKernelspec = 
      simpleKernelspec "Calculator" "calculator" $ \exe connect -> [exe, "kernel", connect]

    -- Print an error message and exit with non-zero exit code if the install failed. 
    handleInstallResult :: InstallResult -> IO ()
    handleInstallResult installResult =
      case installResult of
        InstallSuccessful -> return ()
        InstallFailed reason -> do
          T.hPutStrLn stderr reason
          exitFailure

-- | Run the kernel on ports determined by parsing the connection file provided.
runKernel :: FilePath -> IO ()
runKernel profilePath = do
  Just profile <- readProfile profilePath

  -- Keep track of the current execution using an MVar. In general, kernel state (when it exists)
  -- often needs to be kept in some sort of temporary mutable state.
  execCountVar <- newMVar 1
  serve profile defaultCommHandler $ requestHandler profile execCountVar