egison-tutorial 4.0.1 → 4.1.3
raw patch · 2 files changed
+130/−122 lines, 2 filesdep +exceptionsdep ~egison
Dependencies added: exceptions
Dependency ranges changed: egison
Files
- Main.hs +127/−120
- egison-tutorial.cabal +3/−2
Main.hs view
@@ -1,7 +1,9 @@ module Main where -import Control.Exception (AsyncException(..), catch)+import Control.Exception (AsyncException (..))+import Control.Monad.Catch (catch) import Control.Monad.Except+import Control.Monad.Reader import Data.Version import Data.List@@ -10,83 +12,90 @@ import System.Environment import System.Directory (getHomeDirectory) import System.FilePath ((</>))-import System.Console.Haskeline hiding (handle, catch, throwTo)+import System.Console.Haskeline import System.Console.GetOpt import System.Exit (ExitCode (..), exitWith) import Language.Egison-import qualified Language.Egison.CmdOptions as ET+import qualified Language.Egison.CmdOptions as ET import Language.Egison.Completion (completeEgison) import qualified Language.Egison.Parser.NonS as Parser import qualified Paths_egison_tutorial as P main :: IO () main = do args <- getArgs- let (actions, nonOpts, _) = getOpt Permute options args- let opts = foldl (flip id) defaultOptions actions- case opts of- Options {optShowSections = True} -> putStrLn $ show tutorial- Options {optSection = Just sn, optSubSection = Just ssn} -> do- let sn' = (read sn) :: Int- let ssn' = (read ssn) :: Int- let ret = case tutorial of- Tutorial ss ->- if 0 < sn' && sn' <= length ss- then case nth sn' ss of- Section _ cs ->- if 0 < ssn' && ssn' <= length cs- then showContent $ nth ssn' cs- else "error: content out of range"- else "error: section out of range"- putStrLn ret- Options {optShowHelp = True} -> printHelp- Options {optShowVersion = True} -> printVersionNumber- Options {optPrompt = prompt} -> do- env <- initialEnv ET.defaultOption- case nonOpts of- [] -> showBanner >> repl env prompt- _ -> printHelp+ let (actions, _, _) = getOpt Permute tOptions args+ let tOpts = foldl (flip id) defaultEgisonTutorialOpts actions+ runWithEgisonTutorialOpts tOpts -data Options = Options {- optShowVersion :: Bool,- optShowHelp :: Bool,- optPrompt :: String,- optShowSections :: Bool,- optSection :: Maybe String,- optSubSection :: Maybe String+runWithEgisonTutorialOpts :: EgisonTutorialOpts -> IO ()+runWithEgisonTutorialOpts EgisonTutorialOpts{ tOptShowSections = True } = putStrLn $ show tutorial+runWithEgisonTutorialOpts EgisonTutorialOpts{ tOptSection = Just sn, tOptSubSection = Just ssn } = do+ let sn' = (read sn) :: Int+ let ssn' = (read ssn) :: Int+ let ret = case tutorial of+ Tutorial ss ->+ if 0 < sn' && sn' <= length ss+ then case nth sn' ss of+ Section _ cs ->+ if 0 < ssn' && ssn' <= length cs+ then showContent $ nth ssn' cs+ else "error: content out of range"+ else "error: section out of range"+ putStrLn ret+runWithEgisonTutorialOpts EgisonTutorialOpts{ tOptShowHelp = True } = printHelp+runWithEgisonTutorialOpts EgisonTutorialOpts{ tOptShowVersion = True } = printVersionNumber+runWithEgisonTutorialOpts EgisonTutorialOpts{ tOptPrompt = prompt } = evalRuntimeT ET.defaultOption { optPrompt = prompt } run++run :: RuntimeM ()+run = do+ opts <- ask+ coreEnv <- initialEnv+ mEnv <- fromEvalT $ evalTopExprs coreEnv $ map Load (optLoadLibs opts) ++ map LoadFile (optLoadFiles opts)+ case mEnv of+ Left err -> liftIO $ print err+ Right env -> repl env++data EgisonTutorialOpts = EgisonTutorialOpts {+ tOptShowVersion :: Bool,+ tOptShowHelp :: Bool,+ tOptPrompt :: String,+ tOptShowSections :: Bool,+ tOptSection :: Maybe String,+ tOptSubSection :: Maybe String } -defaultOptions :: Options-defaultOptions = Options {- optShowVersion = False,- optShowHelp = False,- optPrompt = "> ",- optShowSections = False,- optSection = Nothing,- optSubSection = Nothing+defaultEgisonTutorialOpts :: EgisonTutorialOpts+defaultEgisonTutorialOpts = EgisonTutorialOpts {+ tOptShowVersion = False,+ tOptShowHelp = False,+ tOptPrompt = "> ",+ tOptShowSections = False,+ tOptSection = Nothing,+ tOptSubSection = Nothing } -options :: [OptDescr (Options -> Options)]-options = [+tOptions :: [OptDescr (EgisonTutorialOpts -> EgisonTutorialOpts)]+tOptions = [ Option ['v', 'V'] ["version"]- (NoArg (\opts -> opts {optShowVersion = True}))+ (NoArg (\tOpts -> tOpts {tOptShowVersion = True})) "show version number", Option ['h', '?'] ["help"]- (NoArg (\opts -> opts {optShowHelp = True}))+ (NoArg (\tOpts -> tOpts {tOptShowHelp = True})) "show usage information", Option ['p'] ["prompt"]- (ReqArg (\prompt opts -> opts {optPrompt = prompt})+ (ReqArg (\prompt tOpts -> tOpts {tOptPrompt = prompt}) "String") "set prompt string", Option ['l'] ["list"]- (NoArg (\opts -> opts {optShowSections = True}))+ (NoArg (\tOpts -> tOpts {tOptShowSections = True})) "show section list", Option ['s'] ["section"]- (ReqArg (\sn opts -> opts {optSection = Just sn})+ (ReqArg (\sn tOpts -> tOpts {tOptSection = Just sn}) "String") "set section number", Option ['c'] ["subsection"]- (ReqArg (\ssn opts -> opts {optSubSection = Just ssn})+ (ReqArg (\ssn tOpts -> tOpts {tOptSubSection = Just ssn}) "String") "set subsection number" ]@@ -95,7 +104,7 @@ printHelp = do putStrLn "Usage: egison-tutorial [options]" putStrLn ""- putStrLn "Options:"+ putStrLn "EgisonTutorialOpts:" putStrLn " --help Display this information" putStrLn " --version Display egison version information" putStrLn " --prompt string Set prompt of the interpreter"@@ -166,31 +175,32 @@ getNumber n -- |Get Egison expression from the prompt. We can handle multiline input.-getEgisonExprOrNewLine :: Options -> InputT IO (Either Bool (String, EgisonTopExpr))-getEgisonExprOrNewLine opts = getEgisonExprOrNewLine' opts ""+getEgisonExprOrNewLine :: InputT RuntimeM (Either Bool (String, TopExpr))+getEgisonExprOrNewLine = getEgisonExprOrNewLine' "" -getEgisonExprOrNewLine' :: Options -> String -> InputT IO (Either Bool (String, EgisonTopExpr))-getEgisonExprOrNewLine' opts prev = do+getEgisonExprOrNewLine' :: String -> InputT RuntimeM (Either Bool (String, TopExpr))+getEgisonExprOrNewLine' prev = do+ opts <- lift ask mLine <- case prev of "" -> getInputLine $ optPrompt opts- _ -> getInputLine $ replicate (length $ optPrompt opts) ' '+ _ -> getInputLine $ replicate (length (optPrompt opts)) ' ' case mLine of Nothing -> return $ Left False -- The user's input is 'Control-D'. Just [] -> return $ Left True -- The user's input is 'Enter'. Just line -> do let input = prev ++ line- let parsedExpr = Parser.parseTopExpr input+ parsedExpr <- lift $ Parser.parseTopExpr input case parsedExpr of Left err | show err =~ "unexpected end of input" ->- getEgisonExprOrNewLine' opts $ input ++ "\n"+ getEgisonExprOrNewLine' (input ++ "\n") Left err -> do liftIO $ print err- getEgisonExprOrNewLine opts+ getEgisonExprOrNewLine Right topExpr -> return $ Right (input, topExpr) -replSettings :: MonadIO m => FilePath -> Settings m-replSettings home = Settings- { complete = completeEgison+replSettings :: MonadIO m => FilePath -> Env -> Settings m+replSettings home env = Settings+ { complete = completeEgison env , historyFile = Just (home </> ".egison_history") , autoAddHistory = True }@@ -202,52 +212,52 @@ , autoAddHistory = False } -repl :: Env -> String -> IO ()-repl env prompt = do- section <- selectSection tutorial+repl :: Env -> RuntimeM ()+repl env = do+ section <- liftIO $ selectSection tutorial case section of- Section _ cs -> loop env cs True+ Section _ cs -> repl' env cs True where- loop :: Env -> [Content] -> Bool -> IO ()- loop env [] _ = do--- liftIO $ showFinishMessage- liftIO $ repl env prompt- loop env (content:contents) b = (do+ repl' :: Env -> [Content] -> Bool -> RuntimeM ()+ repl' env [] _ = do+ repl env+ repl' env (content:contents) b = (do if b then liftIO $ putStrLn $ show content else return ()- home <- getHomeDirectory- input <- liftIO $ runInputT (replSettings home) $ getEgisonExprOrNewLine defaultOptions+ home <- liftIO $ getHomeDirectory+ input <- runInputT (replSettings home env) $ getEgisonExprOrNewLine case input of -- The user input 'Control-D'. Left False -> do- b <- yesOrNo "Do you want to quit?"+ b <- liftIO $ yesOrNo "Do you want to quit?" if b then return () else do- b <- yesOrNo "Do you want to proceed next?"+ b <- liftIO $ yesOrNo "Do you want to proceed next?" if b- then loop env contents True- else loop env (content:contents) False+ then repl' env contents True+ else repl' env (content:contents) False -- The user input just 'Enter'. Left True -> do- b <- yesOrNo "Do you want to proceed next?"+ b <- liftIO $ yesOrNo "Do you want to proceed next?" if b- then loop env contents True- else loop env (content:contents) False+ then repl' env contents True+ else repl' env (content:contents) False Right (topExpr, _) -> do- result <- liftIO $ runEgisonTopExpr ET.defaultOption env topExpr+ result <- fromEvalT (runTopExprStr env topExpr) case result of Left err -> do liftIO $ putStrLn $ show err- loop env (content:contents) False- Right env' -> loop env' (content:contents) False)+ repl' env (content:contents) False+ Right (Just output, env') -> liftIO (putStrLn output) >> repl' env' (content:contents) False+ Right (Nothing, env') -> repl' env' (content:contents) False) `catch` (\e -> case e of- UserInterrupt -> putStrLn "" >> loop env (content:contents) False- StackOverflow -> putStrLn "Stack over flow!" >> loop env (content:contents) False- HeapOverflow -> putStrLn "Heap over flow!" >> loop env (content:contents) False- _ -> putStrLn "error!" >> loop env (content:contents) False+ UserInterrupt -> liftIO (putStrLn "") >> repl' env (content:contents) False+ StackOverflow -> liftIO (putStrLn "Stack over flow!") >> repl' env (content:contents) False+ HeapOverflow -> liftIO (putStrLn "Heap over flow!") >> repl' env (content:contents) False+ _ -> liftIO (putStrLn "error!") >> repl' env (content:contents) False ) data Tutorial = Tutorial [Section]@@ -291,11 +301,11 @@ tutorial = Tutorial [Section "Arithmetic" [- Content "We can do arithmetic operations with \"+\", \"-\", \"*\", \"/\", \"^\" and \"modulo\"."- ["1 + 2", "30 - 15", "10 * 20", "20 / 5", "2 ^ 10", "modulo 17 4"]+ Content "We can do arithmetic operations with \"+\", \"-\", \"*\", \"/\", and \"^\"."+ ["1 + 2", "30 - 15", "10 * 20", "20 / 5", "2 ^ 10"] [], Content "We support rational numbers."- ["2 / 3 + 1 / 5", "42 / 84"]+ ["2 / 3 + 1 / 5", "4 / 8"] [], Content "We support floating-point numbers, too." ["10.2 + 1.3", "10.2 + 1"]@@ -306,33 +316,24 @@ Content "We can handle lists of numbers.\nWe construct a list by enclosing its elements with \"[]\"." ["[]", "[10]", "[1, 2, 3, 4, 5]"] [],- Content "We can decompose a list using the \"head\" and \"tail\" function."- ["head [1, 2, 3, 4, 5]", "tail [1, 2, 3, 4, 5]", "head (tail [1, 2, 3, 4, 5])"]- ["Try to extract the third element of the list \"[1, 2, 3, 4, 5]\" with \"head\" and \"tail\"."],+ Content "Using the \"sum\" function, we can get the summation of the argument list."+ ["sum []", "sum [10]", "sum [1, 2, 3, 4, 5]"]+ [], Content "Using the \"take\" function, we can extract a head part of a list." ["take 3 [1, 2, 3, 4, 5]", "take 0 [1, 2, 3, 4, 5]"] [], Content "We can handle infinite lists.\nFor example, \"nats\" and \"primes\" are an infinite list that contains all natural numbers and prime numbers respectively.\nTry to extract a head part from them." ["take 10 nats", "take 30 nats", "take 10 primes", "take 30 primes"] ["What is the 100th prime number?"],- Content "We can change an infix operator to a prefix operator by enclosing the operator by \"()\".\nThis notation is similar to the section notation in Haskell."- ["(+) 2 3", "(/ 2) 3", "(2 /) 3"]- [],- Content "We can create functions using the \"lambda\" notation.\nFunctions are written like \"\\x -> ... \".\n\"(\\x -> x + 2)\" is equal to \"(+ 2)\".\n\"(\\x y -> x + y)\" is equal to \"(+)\"."- ["(\\x -> x + 2) 10", "(\\x y -> x + y) 2 3", "(\\x y -> (x + y) / 2) 10 20"]+ Content "We can create functions using the \"lambda\" notation.\nFunctions are written like \"\\x -> ... \"."+ ["(\\x -> x + 2) 10", "(\\x -> x ^ 2) 10"] [], Content "The \"map\" function applies the first argument function to each element of the second argument list.\nThe \"map\" function is one of the most important function in functional programming."- ["take 100 (map (* 2) nats)", "take 100 (map (\\x -> modulo x 3) nats)"]+ ["map (\\x -> x * 2) [1, 2, 3, 4, 5]", "map (\\x -> 1 / x) [1, 2, 3, 4, 5]"] ["Try to create a sequence of numbers \"[1, 1/2, 1/3, 1/4, ..., 1/100]\"."],- Content "The \"foldl\" function gathers together all elements of the third argument list using the operator specified by the first argument.\nThe second argument is an initial value.\nThe \"foldl\" function is also important in functional programming."- ["foldl (+) 0 [1, 2, 3, 4, 5]", "foldl (*) 1 [1, 2, 3, 4, 5]"]- ["Try to get the sum of from 1 to 100."],- Content "Try to calculate \"1 + 1/2 + 1/3 + 1/4 + ... + 1/100\".\nRemember that we can convert a rational number to a floating-point number with \"rtof\"."+ Content "Try to calculate \"1 + (1/2)^2 + (1/3)^2 + (1/4)^2 + ... + (1/100)^2\".\nIn fact, \"1 + (1/2)^2 + (1/3)^2 + (1/4)^2 + ...\" converges to \"pi * pi / 6\".\nRemember that we can convert a rational number to a floating-point number with \"rtof\"." ["rtof (2 / 3)"] [],- Content "Try to calculate \"1 + (1/2)^2 + (1/3)^2 + (1/4)^2 + ... + (1/100)^2\".\nIn fact, \"1 + (1/2)^2 + (1/3)^2 + (1/4)^2 + ...\" converges to \"pi * pi / 6\"."- []- [], Content "This is the end of this section.\nPlease play freely or proceed to the next section.\nThank you for enjoying our tutorial!" [] []@@ -340,14 +341,20 @@ Section "Basics of functional programming" [ Content "We can bind a value to a variable using \":=\" (not \"=\")."- ["x := 10", "x", "y := 1 + x", "y"]+ ["def x := 10", "x", "def y := 1 + x", "y"] [],- Content "We support recursive definitions.\nRecursive definitions enable us to define a list with infinitely many elements."- ["ones := 1 :: ones", "take 100 ones", "nats := 1 :: map (\\n -> n + 1) nats", "take 100 nats", "odds := 1 :: map (\\n -> n + 2) odds", "take 100 odds"]+ Content "We support recursive definitions.\nRecursive definitions enable us to define a list with infinitely many elements.\nThe \"::\" infix operator adds the first argument to the head of the second argument list."+ ["def ones := 1 :: ones", "take 100 ones", "def nats := 1 :: map (\\n -> n + 1) nats", "take 100 nats", "def odds := 1 :: map (\\n -> n + 2) odds", "take 100 odds"] ["Try to define the infinite list of even numbers like [2, 4, 6, 8, 10, ...]."], Content "Let's define functions and test them."- ["increment x := x + 1", "increment 10", "multiply x y := x * y", "multiply 10 20", "fact n := foldl (*) 1 (take n nats)", "fact 10"]+ ["def increment x := x + 1", "increment 10", "def avrage x y := (x + y) / 2", "average 10 20"] [],+ Content "We can change an infix operator to a prefix operator by enclosing the operator by \"()\".\nFor example, \"(+) 2 3\" is equivalent to \"2 + 3\"."+ ["(+) 2 3", "(/) 3 2"]+ [],+ Content "The \"foldl\" function gathers together all elements of the third argument list using the operator specified by the first argument.\nThe second argument is an initial value."+ ["foldl (+) 0 [1, 2, 3, 4, 5]", "foldl (*) 1 [1, 2, 3, 4, 5]", "def sum xs := foldl (+) 0 xs", "sum [1, 2, 3, 4, 5]"]+ ["Try to get the sum of from 1 to 100."], Content "We can compare numbers using functions, \"=\", \"<\", \"<=\", \">\", \">=\".\nThese functions return boolean values, \"True\" and \"False\".\nFunctions that return boolean values are called \"predicates\"." ["1 = 1", "1 < 1", "1 <= 1", "1 > 1", "1 >= 1"] [],@@ -363,7 +370,7 @@ Content "Using the \"zip\" function, we can combine two lists as follows." ["take 100 (zip nats nats)", "take 100 (zip primes primes)"] ["Try to generate the prime table as \"[(1, 2), (2, 3), (3, 5), (4, 7), (5, 11), ...]\"."],- Content "Try to create a Fibonacci sequence \"[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...]\".\n\nHint:\n Replace \"???\" in the following expression to a proper function.\n fibs := 1 :: 1 :: map ??? (zip fibs (tail fibs))"+ Content "Try to create a Fibonacci sequence \"[1, 1, 2, 3, 5, 8, 13, 21, 34, 55, ...]\".\n\nHint:\n Replace \"???\" in the following expression to a proper function.\n def fibs := 1 :: 1 :: map ??? (zip fibs (tail fibs))" [] [], Content "This is the end of this section.\nPlease play freely or proceed to the next section.\nThank you for enjoying our tutorial!"@@ -413,7 +420,7 @@ ], Section "Pattern matching for multisets and sets" [- Content "We can describe pattern matching for multisets and sets.\nWe can change the interpretation of patterns by changing the matcher, the second argument of the matchAll expression.\nThe meaning of the cons pattern (::) is generalized to divide a collection into \"an\" element and the rest."+ Content "We can pattern-match a list as a multiset or set.\nWe can change the interpretation of patterns by changing the matcher, the second argument of the matchAll expression.\nThe meaning of the cons pattern (::) is generalized to divide a collection into \"an\" element and the rest." ["matchAll [1, 2, 3] as list integer with $x :: $xs -> (x, xs)", "matchAll [1, 2, 3] as multiset integer with $x :: $xs -> (x, xs)", "matchAll [1, 2, 3] as set integer with $x :: $xs -> (x, xs)"]@@ -505,13 +512,13 @@ ] [], Content "The function defined using scalar parameters (prepended by \"$\") are automatically mapped to each component of tensors."- ["min $x $y := if x < y then x else y",+ ["def min $x $y := if x < y then x else y", "min [| 1, 2, 3 |]_i [| 10, 20, 30 |]_i", "min [| 1, 2, 3 |]_i [| 10, 20, 30 |]_j" ] [], Content "The function defined using tensor parameters (prepended by \"%\") treats a tensor as a whole.\nIf we prepend "- ["det2 %X := X_1_1 * X_2_2 - X_1_2 * X_2_1",+ ["def det2 %X := X_1_1 * X_2_2 - X_1_2 * X_2_1", "det2 [| [| 2, 1 |], [| 1, 2 |] |]", "det2 [| [| a, b |], [| c, d |] |]" ]@@ -535,10 +542,10 @@ ] [], Content "1-forms on Euclid space and Wedge product are represented as follows.\n\"!\" is effectively used in the definition of Wedge product."- ["dx := [| 1, 0, 0 |]",- "dy := [| 0, 1, 0 |]",- "dz := [| 0, 0, 1 |]",- "wedge %A %B := A !. B",+ ["def dx := [| 1, 0, 0 |]",+ "def dy := [| 0, 1, 0 |]",+ "def dz := [| 0, 0, 1 |]",+ "def wedge %A %B := A !. B", "wedge dx dy" ] [],@@ -548,8 +555,8 @@ ] [], Content "Exterior derivative is defined as follows.\n\"!\" is effectively used in the definition of exterior derivative."- ["params := [| x, y, z |]",- "d %A := !((flip ∂/∂) params A)",+ ["def params := [| x, y, z |]",+ "def d %A := !((flip ∂/∂) params A)", "d (f x y z)", "d (d (f x y z))", "dfNormalize (d (d (f x y z)))"
egison-tutorial.cabal view
@@ -1,5 +1,5 @@ Name: egison-tutorial-Version: 4.0.1+Version: 4.1.3 Synopsis: A tutorial program for the Egison programming language Description: A tutorial program for the Egison programming language. Egison is the programming langugage that realized non-linear pattern-matching against unfree data types.@@ -21,7 +21,7 @@ Executable egison-tutorial default-language: Haskell2010 Main-is: Main.hs- Build-depends: egison >= 4.0.3+ Build-depends: egison >= 4.1.3 , base >= 4.0 && < 5 , haskeline , transformers@@ -29,6 +29,7 @@ , directory , filepath , regex-posix+ , exceptions ghc-options: -Wall -Wno-name-shadowing Other-modules: Paths_egison_tutorial autogen-modules: Paths_egison_tutorial