packages feed

annah (empty) → 1.0.0

raw patch · 8 files changed

+3020/−0 lines, 8 filesdep +Earleydep +annahdep +arraysetup-changed

Dependencies added: Earley, annah, array, base, lens-family-core, morte, optparse-applicative, pipes, system-fileio, system-filepath, text, text-format, transformers

Files

+ LICENSE view
@@ -0,0 +1,24 @@+Copyright (c) 2014 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+    * Redistributions of source code must retain the above copyright notice,+      this list of conditions and the following disclaimer.+    * Redistributions in binary form must reproduce the above copyright notice,+      this list of conditions and the following disclaimer in the documentation+      and/or other materials provided with the distribution.+    * Neither the name of Gabriel Gonzalez nor the names of other contributors+      may be used to endorse or promote products derived from this software+      without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ annah.cabal view
@@ -0,0 +1,72 @@+Name: annah+Version: 1.0.0+Cabal-Version: >=1.8.0.2+Build-Type: Simple+Tested-With: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.2+License: BSD3+License-File: LICENSE+Copyright: 2015 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Bug-Reports: https://github.com/Gabriel439/Haskell-Annah-Library/issues+Synopsis: Medium-level language that desugars to Morte+Description: Annah is a very simple statically typed and purely functional+    lambda calculus with built-in support for:+    .+    * imports via embedding remote expressions+    .+    * mutually recursive data types+    .+    * let expressions+    .+    * natural numbers+    .+    * lists+    .+    * free monads+    .+    * free categories+    .+    Annah is built on top of Morte (a minimalist calculus of constructions),+    meaning that all language features that Annah provides are desugared to+    a pure non-recursive lambda calculus.+    .+    Read the "Annah.Tutorial" module to learn more about how to program using+    Annah.+Category: Compiler+Source-Repository head+    Type: git+    Location: https://github.com/Gabriel439/Haskell-Annah-Library++Library+    Hs-Source-Dirs: src+    Build-Depends:+        base             >= 4        && < 5   ,+        array            >= 0.4.0.0  && < 0.6 ,+        Earley           >= 0.10.1.0 && < 0.12,+        lens-family-core >= 1.0.0    && < 1.3 ,+        morte            >= 1.6.0    && < 1.7 ,+        pipes            >= 4.0.0    && < 4.2 ,+        system-filepath  >= 0.3.1    && < 0.5 ,+        text             >= 0.11.1.0 && < 1.3 ,+        text-format                     < 0.4 ,+        transformers     >= 0.2.0.0  && < 0.5+    Exposed-Modules:+        Annah.Core,+        Annah.Lexer,+        Annah.Parser,+        Annah.Tutorial+    Build-Tools: alex+    GHC-Options: -O2++Executable annah+    Hs-Source-Dirs: exec+    Main-Is: Main.hs+    Build-Depends:+        base                 >= 4        && < 5   ,+        annah                                     ,+        morte                >= 1.6.0    && < 1.7 ,+        optparse-applicative                < 0.13,+        system-filepath      >= 0.3.1    && < 0.5 ,+        system-fileio        >= 0.2.1    && < 0.4 ,+        text                 >= 0.11.1.0 && < 1.3
+ exec/Main.hs view
@@ -0,0 +1,154 @@+{-# LANGUAGE OverloadedStrings #-}++module Main where++import Annah.Core (Data(..), Expr(..), Type(..))+import Control.Applicative ((<|>))+import Control.Exception (Exception, throwIO)+import Control.Monad (forM_)+import Data.Monoid (mempty)+import Data.Text.Lazy (fromStrict)+import Filesystem.Path (FilePath, (</>))+import Morte.Core (Path(..), Var(..))+import Options.Applicative+import Prelude hiding (FilePath)+import System.IO (stderr)++import qualified Annah.Core                as Annah+import qualified Annah.Parser              as Annah+import qualified Data.Text.Lazy            as Text+import qualified Data.Text.Lazy.IO         as Text+import qualified Filesystem+import qualified Filesystem.Path.CurrentOS as Filesystem+import qualified Morte.Core                as Morte+import qualified Morte.Import              as Morte++throws :: Exception e => Either e a -> IO a+throws (Left  e) = throwIO e+throws (Right r) = return r++data Mode = Default | Compile FilePath | Desugar | Types++parser :: Parser Mode+parser+    =   subparser+        (   command "compile"+            (info (helper <*> (Compile <$> parseFilePath))+                (   fullDesc+                <>  header "annah compile - Compile Annah code"+                <>  progDesc "Compile an Annah program located at the given \+                             \file path.  Prefer this subcommand over reading \+                             \from standard input when you want remote \+                             \references to be resolved relative to that \+                             \file's path"+                )+            )+        <>  metavar "compile"+        )+    <|> subparser+        (   command "desugar"+            (info (helper <*> pure Desugar)+                (   fullDesc+                <>  header "annah desugar - Desugar Annah code"+                <>  progDesc "Desugar an Annah program to the equivalent Morte \+                             \program, reading the Annah program from standard \+                             \input and writing the Morte program to standard \+                             \output."+                )+            )+        <>  metavar "desugar"+        )+    <|> subparser+        (   command "types"+            (   info (helper <*> pure Types)+                (   fullDesc+                <>  header "annah types - Compile an Annah datatype definition"+                <>  progDesc "Translate an Annah datatype definition to the \+                             \equivalent set of files, reading the datatype \+                             \definition from standard input.  This creates \+                             \one output directory for each type with one file \+                             \underneath each directory per data constructor \+                             \associated with that type."+                )+            )+        <>  metavar "types"+        )+    <|> pure Default+  where+    parseFilePath =+        fmap Filesystem.decodeString+            (strArgument (metavar "FILEPATH" <> help "Path to file to compile"))++main :: IO ()+main = do+    mode <- execParser $ info (helper <*> parser)+        (   fullDesc+        <>  header "annah - A strongly typed, purely functional language"+        <>  progDesc "Annah is a medium-level language that is a superset of \+                     \Morte.  Use this compiler to desugar Annah code to Morte \+                     \code."+        )+    case mode of+        Default -> do+            txt <- Text.getContents+            ae  <- throws (Annah.exprFromText txt)+            let me = Annah.desugar ae+            -- Only statically link the Morte expression for type-checking+            me' <- Morte.load Nothing me+            mt  <- throws (Morte.typeOf me')+            -- Return the dynamically linked Morte expression+            Text.putStrLn (Morte.pretty (Morte.normalize me))+        Compile file -> do+            txt <- Text.readFile (Filesystem.encodeString file)+            ae  <- throws (Annah.exprFromText txt)+            let me = Annah.desugar ae+            -- Only statically link the Morte expression for type-checking+            me' <- Morte.load (Just (File file)) me+            mt  <- throws (Morte.typeOf me')+            -- Return the dynamically linked Morte expression+            Text.putStrLn (Morte.pretty (Morte.normalize me))+        Desugar -> do+            txt <- Text.getContents+            ae  <- throws (Annah.exprFromText txt)+            Text.putStrLn (Morte.pretty (Annah.desugar ae))+        Types -> do+            -- TODO: Handle duplicate type and data constructor names+            txt <- Text.getContents+            ts  <- throws (Annah.typesFromText txt)+            let write file txt =+                    Filesystem.writeTextFile file (Text.toStrict txt <> "\n")+            let named = Filesystem.fromText . Text.toStrict+            forM_ ts (\t -> do+                let typeDir = named (typeName t)+                let typeAnnahFile = named (typeName t <> ".annah")+                let typeMorteFile = typeDir </> "@"+                let foldAnnahFile = typeDir </> named (typeFold t <> ".annah")+                let foldMorteFile = typeDir </> named (typeFold t)++                Filesystem.createDirectory True typeDir+                write typeAnnahFile (txt <> "in   " <> typeName t)+                let e0 = Family ts (Var (V (typeName t) 0))+                let typeTxt = Morte.pretty (Morte.normalize (Annah.desugar e0))+                write typeMorteFile typeTxt++                if typeFold t /= "_"+                    then do+                        write foldAnnahFile (txt <> "in   " <> typeFold t)+                        let e1 = Family ts (Var (V (typeFold t) 0))+                        let foldTxt =+                                Morte.pretty (Morte.normalize (Annah.desugar e1))+                        write foldMorteFile foldTxt+                    else return ()++                forM_ (typeDatas t) (\d -> do+                    let dataAnnahName = named (dataName d <> ".annah")+                    let dataMorteName = named (dataName d)+                    let dataAnnahFile = typeDir </> dataAnnahName+                    let dataMorteFile = typeDir </> dataMorteName++                    write dataAnnahFile (txt <> "in   " <> dataName d)++                    let e2 = Family ts (Var (V (dataName d) 0))+                    let dataTxt =+                            Morte.pretty (Morte.normalize (Annah.desugar e2))+                    write dataMorteFile dataTxt ) )
+ src/Annah/Core.hs view
@@ -0,0 +1,594 @@+{-# LANGUAGE OverloadedStrings  #-}+{-# OPTIONS_GHC -Wall #-}++{-| This module contains the core machinery for the Annah language, which is a+    medium-level language that desugars to Morte.++    The main high-level features that Annah does not provide compared to Haskell+    are:++    * type classes++    * type inference++    You cannot type-check or normalize Annah expressions directly.  Instead,+    you `desugar` Annah expressions to Morte, and then type-check or normalize+    the Morte expressions using `M.typeOf` and `M.normalize`.++    Annah does everything through Morte for two reasons:++    * to ensure the soundness of type-checking and normalization, and:++    * to interoperate with other languages that compile to Morte.++    The typical workflow is:++    * You parse a `Text` source using `Annah.Parser.exprFromText`++    * You `desugar` the Annah expression to Morte++    * You resolve all imports using `M.load`++    * You type-check the Morte expression using `M.typeOf`++    * You `M.normalize` the Morte expression+-}++module Annah.Core (+    -- * Syntax+      M.Var(..)+    , M.Const(..)+    , Arg(..)+    , Let(..)+    , Data(..)+    , Type(..)+    , Bind(..)+    , Expr(..)++    -- * Desugaring+    , desugar+    , desugarFamily+    , desugarNatural+    , desugarDo+    , desugarList+    , desugarPath+    , desugarLets++    ) where++import Control.Applicative (pure, empty)+import Data.String (IsString(..))+import Data.Text.Lazy (Text)+import qualified Morte.Core as M+import Prelude hiding (pi)++{-| Argument for function or constructor definitions++> Arg "_" _A  ~       _A+> Arg  x  _A  ~  (x : _A)+-}+data Arg = Arg+    { argName :: Text+    , argType :: Expr+    } deriving (Show)++{-|+> Let f [a1, a2] _A rhs  ~  let f a1 a2 : _A = rhs+-}+data Let = Let+    { letName :: Text+    , letArgs :: [Arg]+    , letType :: Expr+    , letRhs  :: Expr+    } deriving (Show)++{-|+> Type t [d1, d2] f  ~  type t d1 d2 fold f+-}+data Type = Type+    { typeName  :: Text+    , typeDatas :: [Data]+    , typeFold  :: Text+    } deriving (Show)++{-|+> Data c [a1, a2]  ~  data c a1 a2+-}+data Data = Data+    { dataName :: Text+    , dataArgs :: [Arg]+    } deriving (Show)++{-|+> Bind arg e  ~  arg <- e;+-}+data Bind = Bind+    { bindLhs :: Arg+    , bindRhs :: Expr+    } deriving (Show)++-- | Syntax tree for expressions+data Expr+    -- | > Const c                         ~  c+    = Const M.Const+    -- | > Var (V x 0)                     ~  x+    --   > Var (V x n)                     ~  x@n+    | Var M.Var+    -- | > Lam x     _A  b                 ~  λ(x : _A) →  b+    | Lam Text Expr Expr+    -- | > Pi x      _A _B                 ~  ∀(x : _A) → _B+    | Pi  Text Expr Expr+    -- | > App f a                         ~  f a+    | App Expr Expr+    -- | > Annot a _A                      ~  a : _A+    | Annot Expr Expr+    -- | > Lets [l1, l2] e                 ~  l1 l2 in e+    | Lets [Let] Expr+    -- | > Family f e                      ~  f in e+    | Family [Type] Expr+    -- | > Natural n                       ~  n+    | Natural Integer+    -- | > List t [x, y, z]                ~  [nil t,x,y,z]+    | List Expr [Expr]+    -- | > Path c [(o1, m1), (o2, m2)] o3  ~  [id c {o1} m1 {o2} m2 {o3}]+    | Path Expr [(Expr, Expr)] Expr+    -- | > Do m [b1, b2] b3                ~  do m { b1 b2 b3 }+    | Do Expr [Bind] Bind+    | Embed M.Path+    deriving (Show)++instance IsString Expr where+    fromString str = Var (fromString str)++-- | Convert an Annah expression to a Morte expression+desugar+    :: Expr+    -- ^ Annah expression+    -> M.Expr M.Path+    -- ^ Morte expression+desugar (Const c     ) = M.Const c+desugar (Var v       ) = M.Var   v+desugar (Lam x _A  b ) = M.Lam x (desugar _A) (desugar  b)+desugar (Pi  x _A _B ) = M.Pi  x (desugar _A) (desugar _B)+desugar (App f a     ) = M.App (desugar f) (desugar a)+desugar (Embed  p    ) = M.Embed p+desugar (Annot a _A  ) = desugar (Lets [Let "x" [] _A a] "x")+desugar (Lets ls e   ) = desugarLets  ls               e+desugar (Family ts e ) = desugarLets (desugarFamily ts) e+desugar (Natural n   ) = desugarNatural n+desugar (List t es   ) = desugarList t es+desugar (Path t oms o) = desugarPath t oms o+desugar (Do m bs b   ) = desugarDo m bs b++{-| Convert a natural number to a Morte expression++    For example, this natural number:++> 4++    ... desugars to this Morte expression:++>     λ(Nat  : *                  )+> →   λ(Succ : ∀(pred : Nat) → Nat)+> →   λ(Zero : Nat                )+> →   Succ (Succ (Succ (Succ Zero)))+-}+desugarNatural :: Integer -> M.Expr M.Path+desugarNatural n0 =+    M.Lam "Nat" (M.Const M.Star)+        (M.Lam "Succ" (M.Pi "pred" (M.Var (M.V "Nat" 0)) (M.Var (M.V "Nat" 0)))+            (M.Lam "Zero" (M.Var (M.V "Nat" 0))+                (go0 n0) ) )+  where+    go0 n | n <= 0    = M.Var (M.V "Zero" 0)+          | otherwise = M.App (M.Var (M.V "Succ" 0)) (go0 (n - 1))++{-| Convert a list into a Morte expression++    For example, this list:++> [nil Bool, True, False, False]++    ... desugars to this Morte expression:++>     λ(List : *)+> →   λ(Cons : ∀(head : Bool) → ∀(tail : List) → List)+> →   λ(Nil : List)+> →   Cons True (Cons False (Cons False Nil))+-}+desugarList :: Expr -> [Expr] -> M.Expr M.Path+desugarList e0 ts0 =+    M.Lam "List" (M.Const M.Star)+        (M.Lam "Cons" (M.Pi "head" (desugar0 e0) (M.Pi "tail" "List" "List"))+            (M.Lam "Nil" "List" (go ts0)) )+  where+    go  []    = "Nil"+    go (t:ts) = M.App (M.App "Cons" (desugar1 t)) (go ts)++    desugar0 = M.shift 1 "List" . desugar++    desugar1 = M.shift 1 "List" . M.shift 1 "Cons" . M.shift 1 "Nil" . desugar++{-| Convert a path into a Morte expression++    For example, this path:++> [id cat {a} f {b} g {c}]++    ... desugars to this Morte expression:++>     λ(Path : ∀(a : *) → ∀(b : *) → *)+> →   λ(  Step+>     :   ∀(a : *)+>     →   ∀(b : *)+>     →   ∀(c : *)+>     →   ∀(head : cat a b)+>     →   ∀(tail : Path b c)+>     →   Path a c+>     )+> →   λ(End : ∀(a : *) → Path a a)+> →   Step a b c f (Step b c c g (End c))+-}+desugarPath+    ::  Expr+    ->  [(Expr, Expr)]+    ->  Expr+    ->  M.Expr M.Path+desugarPath c0 oms0 o0 =+    M.Lam "Path"+        (M.Pi "a" (M.Const M.Star) (M.Pi "b" (M.Const M.Star) (M.Const M.Star)))+        (M.Lam "Step"+            (M.Pi "a" (M.Const M.Star)+                (M.Pi "b" (M.Const M.Star)+                    (M.Pi "c" (M.Const M.Star)+                        (M.Pi "head" (M.App (M.App (desugar0 c0) "a") "b")+                            (M.Pi "tail" (M.App (M.App "Path" "b") "c")+                                (M.App (M.App "Path" "a") "c") ) ) ) ) )+            (M.Lam "End"+                (M.Pi "a" (M.Const M.Star) (M.App (M.App "Path" "a") "a"))+                (go oms0) ) )+  where+    desugar0+        =   M.shift 1 "Path"+        .   M.shift 1 "a"+        .   M.shift 1 "b"+        .   M.shift 1 "c"+        .   desugar+    desugar1+        =   M.shift 1 "Path"+        .   M.shift 1 "Step"+        .   M.shift 1 "End"+        .   desugar++    go []                         = M.App "End" (desugar1 o0)+    go [(o1, m1)]                 =+        M.App (M.App (M.App (M.App (M.App "Step" o1') o0') o0') m1') (go [] )+      where+        o0' = desugar1 o0+        o1' = desugar1 o1+        m1' = desugar1 m1+    go ((o1, m1):oms@((o2, _):_)) =+        M.App (M.App (M.App (M.App (M.App "Step" o1') o2') o0') m1') (go oms)+      where+        o0' = desugar1 o0+        o1' = desugar1 o1+        o2' = desugar1 o2+        m1' = desugar1 m1++{-| Convert a command (i.e. do-notation) into a Morte expression++    For example, this command:++> do m+> {   x0 : _A0 <- e0;+>     x1 : _A1 <- e1;+> }++    .. desugars to this Morte expression:++>     λ(Cmd : *)+> →   λ(Bind : ∀(b : *) → m b → (b → Cmd) → Cmd)+> →   λ(Pure : ∀(x1 : _A1) → Cmd)+> →   Bind _A0 e0+>     (   λ(x0 : _A0)+>     →   Bind _A1 e1+>         Pure+>     )+-}+desugarDo :: Expr -> [Bind] -> Bind -> M.Expr M.Path+desugarDo m bs0 (Bind (Arg x0 _A0) e0) =+    M.Lam "Cmd" (M.Const M.Star)+        (M.Lam "Bind"+            (M.Pi "b" (M.Const M.Star)+                (M.Pi "_" (M.App (desugar0 m) "b")+                    (M.Pi "_" (M.Pi "_" "b" "Cmd") "Cmd") ) )+            (M.Lam "Pure" (M.Pi x0 (desugar1 _A0) "Cmd")+                (go bs0 (0 :: Int) (0 :: Int)) ) )+  where+    desugar0+        = M.shift 1 "b"+        . M.shift 1 "Cmd"+        . desugar++    desugar1+        = M.shift 1 "Bind"+        . M.shift 1 "Cmd"+        . desugar++    desugar2+        = M.shift 1 "Pure"+        . M.shift 1 "Bind"+        . M.shift 1 "Cmd"+        . desugar++    go  []                    numPure numBind =+        M.App+            (M.App (M.App (M.Var (M.V "Bind" numBind)) (desugar2 _A0))+                (desugar2 e0) )+            (M.Var (M.V "Pure" numPure))+    go (Bind (Arg x _A) e:bs) numPure numBind = numBind' `seq` numPure' `seq`+        M.App+            (M.App+                (M.App (M.Var (M.V "Bind" numBind)) (desugar2 _A))+                (desugar2 e) )+            (M.Lam x (desugar2 _A) (go bs numBind' numPure'))+      where+        numBind' = if x == "Bind" then numBind + 1 else numBind+        numPure' = if x == "Pure" then numPure + 1 else numPure++{-| Convert a let expression into a Morte expression++    For example, this let expression:++> let f0 (x00 : _A00) ... (x0j : _A0j) _B0 = b0+> ..+> let fi (xi0 : _Ai0) ... (xij : _Aij) _Bi = bi+> in  e++    ... desugars to this Morte expression:++> (   \(f0 : forall (x00 : _A00) -> ... -> forall (x0j : _A0j) -> _B0)+> ->  ...+> ->  \(fi : forall (xi0 : _Ai0) -> ... -> forall (xij : _Aij) -> _Bi)+> ->  e+> )+>+> (\(x00 : _A00) -> ... -> \(x0j : _A0j) -> b0)+> ...+> (\(xi0 : _Ai0) -> ... -> \(xij : _Aij) -> bi)++-}+desugarLets :: [Let] -> Expr -> M.Expr M.Path+desugarLets lets e = apps+  where+    -- > (   \(f0 : forall (x00 : _A00) -> ... -> forall (x0j : _A0j) -> _B0)+    -- > ->  ...+    -- > ->  \(fi : forall (xi0 : _Ai0) -> ... -> forall (xij : _Aij) -> _Bi)+    -- > ->  e+    -- > )+    lams = foldr+        (\(Let fn args _Bn _) rest ->+            -- > forall (xn0 : _An0) -> ... -> forall (xnj : _Anj) -> _Bn+            let rhsType = pi args _Bn++            -- > \(fn : rhsType) -> rest+            in  M.Lam fn (desugar rhsType) rest )+        (desugar e)+        lets++    -- > lams+    -- > (\(x00 : _A00) -> ... -> \(x0j : _A0j) -> b0)+    -- > ...+    -- > (\(xi0 : _Ai0) -> ... -> \(xij : _Aij) -> bi)+    apps = foldr+        (\(Let _ args _ bn) rest ->+            -- > rest (\(xn0 : _An0) -> ... -> \(xnj : _Anj) -> bn)+            M.App rest (desugar (lam args bn)) )+        lams+        (reverse lets)++-- | A type or data constructor+data Cons = Cons+    { consName :: Text+    , consArgs :: [Arg]+    , consType :: Expr+    }++{-| This translates datatype definitions to let expressons using the+    Boehm-Berarducci encoding.++    For example, this mutually recursive datatype definition:++> type Even+> data Zero+> data SuccE (predE : Odd)+> fold foldEven+> +> type Odd+> data SuccO (predO : Even)+> fold foldOdd+> +> in SuccE++    ... desugars to seven let expressions:++> let Even : * = ...+> let Odd  : *+> let Zero : Even = ...+> let SuccE : ∀(predE : Odd ) → Even = ...+> let SuccO : ∀(predO : Even) → Odd  = ...+> let foldEven : ∀(x : Even) → ... = ...+> let foldOdd  : ∀(x : Odd ) → ... = ...+> in  SuccE++    ... and normalizes to:++>     λ(  predE+>     :   ∀(Even  : *)+>     →   ∀(Odd   : *)+>     →   ∀(Zero  : Even)+>     →   ∀(SuccE : ∀(predE : Odd ) → Even)+>     →   ∀(SuccO : ∀(predO : Even) → Odd)+>     →   Odd+>     )+> →   λ(Even : *)+> →   λ(Odd : *)+> →   λ(Zero : Even)+> →   λ(SuccE : ∀(predE : Odd) → Even)+> →   λ(SuccO : ∀(predO : Even) → Odd)+> →   SuccE (predE Even Odd Zero SuccE SuccO)++-}++desugarFamily :: [Type] -> [Let]+desugarFamily familyTypes = typeLets ++ dataLets ++ foldLets+{-  Annah permits data constructors to have duplicate names and Annah also+    permits data constructors to share the same name as type constructors.  A+    lot of the complexity of this code is due to avoiding name collisions.++    Constructor fields can also have duplicate field names, too.  This is+    particularly useful for constructors with multiple fields where the user+    omits the field name and defaults to @\"_\"@, like in this example:++    >     \(a : *)+    > ->  \(b : *)+    > ->  type Pair+    >     data MakePair a b+    >     in   MakePair++    ... which compiles to:++    >     \(a : *)+    > ->  \(b : *)+    > ->  \(_ : a)+    > ->  \(_ : b)+    > ->  \(Pair : *)+    > ->  \(MakePair : a -> b -> Pair)+    > ->  MakePair _@1 _+-}+  where+    typeConstructors :: [Cons]+    typeConstructors = do+        t <- familyTypes+        return (Cons (typeName t) [] (Const M.Star))++    dataConstructors :: [Cons]+    dataConstructors = do+        (tsBefore , t, tsAfter) <- zippers familyTypes+        (dsBefore1, d, _      ) <- zippers (typeDatas t)+        let dsBefore0 = do+                t' <- tsBefore+                typeDatas t'+        let names1  = map typeName tsAfter+        let names2  = map dataName dsBefore0+        let names3  = map dataName dsBefore1+        let names4  = map argName (dataArgs d)+        let typeVar =+                typeName t `isShadowedBy` (names1 ++ names2 ++ names3 ++ names4)+        return (Cons (dataName d) (dataArgs d) typeVar)++    constructors :: [Cons]+    constructors = typeConstructors ++ dataConstructors++    makeRhs piOrLam con = foldr cons con constructors+      where+        cons (Cons x args _A) = piOrLam x (pi args _A)++    typeLets, foldLets :: [Let]+    (typeLets, foldLets) = unzip (do+        let folds = map typeFold familyTypes+        ((_, t, tsAfter), fold) <- zip (zippers typeConstructors) folds+        let names1   = map consName tsAfter+        let names2   = map consName dataConstructors+        let con      = consName t `isShadowedBy` (names1 ++ names2)+        let typeRhs  = makeRhs Pi con+        let foldType = Pi  "x" con      typeRhs+        let foldRhs  = Lam "x" typeRhs  "x"+        return ( Let (consName t) [] (consType t) typeRhs+               , Let  fold        []  foldType    foldRhs+               ) )++    -- TODO: Enforce that argument types are `Var`s?+    desugarType :: Expr -> Maybe ([Arg], Expr, Expr)+    desugarType   (Pi x _A e      ) = do+        ~(args, f, f') <- desugarType e+        return (Arg x _A:args, f, f')+    desugarType f@(Var (M.V x0 n0)) = do+        f' <- go0 dataConstructors x0 n0+        return ([], f, f')+      where+        go0 (d:ds) x n | consName d == x =+            if n > 0 then go0 ds x $! n - 1 else empty+                       | otherwise       = go0 ds x n+        go0  []    x n                   = go1 (reverse typeLets) x n++        go1 (t:ts) x n | letName  t == x =+            if n > 0 then go1 ts x $! n - 1 else pure (letRhs t)+                       | otherwise       = go1 ts x n+        go1  []    _ _                   = empty+    desugarType _ = empty++    consVars :: [Text] -> [Expr]+    consVars argNames = do+        (_, name, namesAfter) <- zippers (map consName constructors)+        return (name `isShadowedBy` (argNames ++ namesAfter))++    dataLets :: [Let]+    dataLets = do+        (_, d, dsAfter) <- zippers dataConstructors+        let conVar  = consName d `isShadowedBy` map consName dsAfter+        let conArgs = do+                (_, arg, argsAfter) <- zippers (consArgs d)+                let names1 = map argName  argsAfter+                let names2 = map consName constructors+                return (case desugarType (argType arg) of+                    Nothing           -> argVar+                      where+                        names = names1 ++ names2+                        argVar = argName arg `isShadowedBy` names+                    Just (args, _, _) ->+                        lam args (apply argVar (argExprs ++ consVars names3))+                      where+                        names3 = map argName args+                        names = names1 ++ names2 ++ names3+                        argVar = argName arg `isShadowedBy` names+                        argExprs = do+                            (_, name, namesAfter) <- zippers names3+                            return (name `isShadowedBy` namesAfter) )+        let (lhsArgs, rhsArgs) = unzip (do+                arg@(Arg x _A) <- consArgs d+                return (case desugarType _A of+                    Just (args, _B, _B') -> (lhsArg, rhsArg)+                      where+                        lhsArg = Arg x (pi args _B )+                        rhsArg = Arg x (pi args _B')+                    Nothing              -> (   arg,    arg) ) )+        let letType' = pi  lhsArgs (consType d)+        let letRhs'  = lam rhsArgs (makeRhs Lam (apply conVar conArgs))+        return (Let (consName d) [] letType' letRhs')++-- | Apply an expression to a list of arguments+apply :: Expr -> [Expr] -> Expr+apply f as = foldr (flip App) f (reverse as)++{-| Compute the correct DeBruijn index for a synthetic `Var` (@x@) by providing+    all variables bound in between when @x@ is introduced and when @x@ is used.+-}+isShadowedBy :: Text -> [Text] -> Expr+x `isShadowedBy` vars = Var (M.V x (length (filter (== x) vars)))++pi, lam :: [Arg] -> Expr -> Expr+pi  args e = foldr (\(Arg x _A) -> Pi  x _A) e args+lam args e = foldr (\(Arg x _A) -> Lam x _A) e args++-- | > zippers [1, 2, 3] = [([], 1, [2, 3]), ([1], 2, [3]), ([2, 1], 3, [])]+zippers :: [a] -> [([a], a, [a])]+zippers  []           = []+zippers (stmt:stmts') = z:go z+  where+    z = ([], stmt, stmts')++    go ( _, _, []  ) = []+    go (ls, m, r:rs) = z':go z'+      where+        z' = (m:ls, r, rs)
+ src/Annah/Lexer.x view
@@ -0,0 +1,215 @@+{+{-# LANGUAGE OverloadedStrings #-}++-- | Lexing logic for the Annah language+module Annah.Lexer (+    -- * Lexer+    lexExpr,++    -- * Types+    Token(..),+    Position(..),+    LocatedToken(..)+    ) where++import Control.Monad.Trans.State.Strict (State)+import Data.Bits (shiftR, (.&.))+import Data.Char (ord, digitToInt, isDigit)+import Data.Int (Int64)+import Data.Text.Lazy (Text)+import Data.Word (Word8)+import Filesystem.Path.CurrentOS (FilePath, fromText)+import Lens.Family.State.Strict ((.=), (+=))+import Pipes (Producer, for, lift, yield)+import Prelude hiding (FilePath)++import qualified Control.Monad.Trans.State.Strict as State+import qualified Data.Text.Lazy                   as Text++}++$digit = 0-9++-- Same as Haskell+$opchar = [\!\#\$\%\&\*\+\.\/\<\=\>\?\@\\\^\|\-\~]++$fst   = [A-Za-z_]+$label = [A-Za-z0-9_]++$nonwhite       = ~$white+$whiteNoNewline = $white # \n++$path = [$label \\\/\.]++tokens :-++    $whiteNoNewline+                  ;+    \n                              { \_    -> lift (do+                                        line   += 1+                                        column .= 0 )                          }+    "--".*                          ;+    "("                             { \_    -> yield OpenParen                 }+    ")"                             { \_    -> yield CloseParen                }+    "{"                             { \_    -> yield OpenBrace                 }+    "}"                             { \_    -> yield CloseBrace                }+    "[nil"                          { \_    -> yield OpenList                  }+    "[id"                           { \_    -> yield OpenPath                  }+    "]"                             { \_    -> yield CloseBracket              }+    ","                             { \_    -> yield Comma                     }+    ":"                             { \_    -> yield Colon                     }+    ";"                             { \_    -> yield Semicolon                 }+    "@"                             { \_    -> yield At                        }+    "*"                             { \_    -> yield Star                      }+    "BOX" | "□"                     { \_    -> yield Box                       }+    "->" | "→"                      { \_    -> yield Arrow                     }+    "<-" | "←"                      { \_    -> yield LArrow                    }+    "\/" | "|~|" | "forall" | "∀" | "Π" { \_ -> yield Pi                       }+    "\" | "λ"                       { \_    -> yield Lambda                    }+    "type"                          { \_    -> yield Type                      }+    "fold"                          { \_    -> yield Fold                      }+    "data"                          { \_    -> yield Data                      }+    "let"                           { \_    -> yield Let                       }+    "="                             { \_    -> yield Equals                    }+    "in"                            { \_    -> yield In                        }+    "do"                            { \_    -> yield Do                        }+    $digit+                         { \text -> yield (Number (toInt text))     }+    $fst $label* | "(" $opchar+ ")" { \text -> yield (Label text)              }+    "https://" $nonwhite+           { \text -> yield (URL text)                }+    "http://" $nonwhite+            { \text -> yield (URL text)                }+    "/" $nonwhite+                  { \text -> yield (File (toFile 0 text))    }+    "./" $nonwhite+                 { \text -> yield (File (toFile 2 text))    }+    "../" $nonwhite+                { \text -> yield (File (toFile 0 text))    }++{+toInt :: Text -> Int+toInt = Text.foldl' (\x c -> 10 * x + digitToInt c) 0++toFile :: Int64 -> Text -> FilePath+toFile n = fromText . Text.toStrict . Text.drop n++trim :: Text -> Text+trim = Text.init . Text.tail++-- This was lifted almost intact from the @alex@ source code+encode :: Char -> (Word8, [Word8])+encode c = (fromIntegral h, map fromIntegral t)+  where+    (h, t) = go (ord c)++    go n+        | n <= 0x7f   = (n, [])+        | n <= 0x7ff  = (0xc0 + (n `shiftR` 6), [0x80 + n .&. 0x3f])+        | n <= 0xffff =+            (   0xe0 + (n `shiftR` 12)+            ,   [   0x80 + ((n `shiftR` 6) .&. 0x3f)+                ,   0x80 + n .&. 0x3f+                ]+            )+        | otherwise   =+            (   0xf0 + (n `shiftR` 18)+            ,   [   0x80 + ((n `shiftR` 12) .&. 0x3f)+                ,   0x80 + ((n `shiftR` 6) .&. 0x3f)+                ,   0x80 + n .&. 0x3f+                ]+            )++-- | The cursor's location while lexing the text+data Position = P+    { lineNo    :: {-# UNPACK #-} !Int+    , columnNo  :: {-# UNPACK #-} !Int+    } deriving (Show)++-- line :: Lens' Position Int+line :: Functor f => (Int -> f Int) -> Position -> f Position+line k (P l c) = fmap (\l' -> P l' c) (k l)++-- column :: Lens' Position Int+column :: Functor f => (Int -> f Int) -> Position -> f Position+column k (P l c) = fmap (\c' -> P l c') (k c)++{- @alex@ does not provide a `Text` wrapper, so the following code just modifies+   the code from their @basic@ wrapper to work with `Text`++   I could not get the @basic-bytestring@ wrapper to work; it does not correctly+   recognize Unicode regular expressions.+-}+data AlexInput = AlexInput+    { prevChar  :: Char+    , currBytes :: [Word8]+    , currInput :: Text+    }++alexGetByte :: AlexInput -> Maybe (Word8,AlexInput)+alexGetByte (AlexInput c bytes text) = case bytes of+    b:ytes -> Just (b, AlexInput c ytes text)+    []     -> case Text.uncons text of+        Nothing       -> Nothing+        Just (t, ext) -> case encode t of+            (b, ytes) -> Just (b, AlexInput t ytes ext)++alexInputPrevChar :: AlexInput -> Char+alexInputPrevChar = prevChar++{-| Convert a text representation of an expression into a stream of tokens++    `lexExpr` keeps track of position and returns the remainder of the input if+    lexing fails.+-}+lexExpr :: Text -> Producer LocatedToken (State Position) (Maybe Text)+lexExpr text = for (go (AlexInput '\n' [] text)) tag+  where+    tag token = do+        pos <- lift State.get+        yield (LocatedToken token pos)++    go input = case alexScan input 0 of+        AlexEOF                        -> return Nothing+        AlexError (AlexInput _ _ text) -> return (Just text)+        AlexSkip  input' len           -> do+            lift (column += len)+            go input'+        AlexToken input' len act       -> do+            act (Text.take (fromIntegral len) (currInput input))+            lift (column += len)+            go input'++-- | A `Token` augmented with `Position` information+data LocatedToken = LocatedToken+    { token    ::                !Token+    , position :: {-# UNPACK #-} !Position+    } deriving (Show)++-- | Token type, used to communicate between the lexer and parser+data Token+    = OpenParen+    | CloseParen+    | OpenBrace+    | CloseBrace+    | OpenList+    | OpenPath+    | CloseBracket+    | Period+    | Comma+    | Colon+    | Semicolon+    | At+    | Star+    | Box+    | Arrow+    | LArrow+    | Lambda+    | Pi+    | Type+    | Fold+    | Data+    | Let+    | Equals+    | In+    | Do+    | Label Text+    | Number Int+    | File FilePath+    | URL Text+    | EOF+    deriving (Eq, Show)+}
+ src/Annah/Parser.hs view
@@ -0,0 +1,260 @@+{-# LANGUAGE DeriveDataTypeable #-}+{-# LANGUAGE OverloadedStrings  #-}+{-# LANGUAGE RankNTypes         #-}+{-# LANGUAGE RecursiveDo        #-}++-- | Parsing logic for the Morte language++module Annah.Parser (+    -- * Parser+    exprFromText,+    typesFromText,++    -- * Errors+    ParseError(..),+    ParseMessage(..)+    ) where++import Annah.Core+import Annah.Lexer (Position, Token, LocatedToken(..))+import Control.Applicative hiding (Const)+import Control.Exception (Exception)+import Control.Monad.Trans.Class  (lift)+import Control.Monad.Trans.Except (Except, throwE, runExceptT)+import Control.Monad.Trans.State.Strict (evalState, get)+import Data.Monoid+import Data.Text.Buildable (Buildable(..))+import Data.Text.Lazy (Text)+import Data.Text.Lazy.Builder (toLazyText)+import Data.Typeable (Typeable)+import Morte.Core (Path(..))+import Filesystem.Path.CurrentOS (FilePath)+import Prelude hiding (FilePath)+import Text.Earley++import qualified Annah.Lexer    as Lexer+import qualified Pipes.Prelude  as Pipes+import qualified Data.Text.Lazy as Text++match :: Token -> Prod r Token LocatedToken Token+match t = fmap Lexer.token (satisfy predicate) <?> t+  where+    predicate (LocatedToken t' _) = t == t'++label :: Prod r e LocatedToken Text+label = fmap unsafeFromLabel (satisfy isLabel)+  where+    isLabel (LocatedToken (Lexer.Label _) _) = True+    isLabel  _                               = False++    unsafeFromLabel (LocatedToken (Lexer.Label l) _) = l++number :: Prod r e LocatedToken Int+number = fmap unsafeFromNumber (satisfy isNumber)+  where+    isNumber (LocatedToken (Lexer.Number _) _) = True+    isNumber  _                                = False++    unsafeFromNumber (LocatedToken (Lexer.Number n) _) = n++file :: Prod r e LocatedToken FilePath+file = fmap unsafeFromFile (satisfy isFile)+  where+    isFile (LocatedToken (Lexer.File _) _) = True+    isFile  _                              = False++    unsafeFromFile (LocatedToken (Lexer.File n) _) = n++url :: Prod r e LocatedToken Text+url = fmap unsafeFromURL (satisfy isURL)+  where+    isURL (LocatedToken (Lexer.URL _) _) = True+    isURL  _                             = False++    unsafeFromURL (LocatedToken (Lexer.URL n) _) = n++sepBy1 :: Alternative f => f a -> f b -> f [a]+sepBy1 x sep = (:) <$> x <*> many (sep *> x)++sepBy :: Alternative f => f a -> f b -> f [a]+sepBy x sep = sepBy1 x sep <|> pure []++expr+    :: Grammar r+        (Prod r Token LocatedToken Expr, Prod r Token LocatedToken [Type])+expr = mdo+    expr0 <- rule+        (   Annot <$> expr1 <*> (match Lexer.Colon *> expr0)+        <|> expr1+        )+    expr1 <- rule+        (       Lam+            <$> (match Lexer.Lambda *> match Lexer.OpenParen *> label)+            <*> (match Lexer.Colon *> expr1)+            <*> (match Lexer.CloseParen *> match Lexer.Arrow *> expr1)+        <|>     Pi+            <$> (match Lexer.Pi *> match Lexer.OpenParen *> label)+            <*> (match Lexer.Colon *> expr1)+            <*> (match Lexer.CloseParen *> match Lexer.Arrow *> expr1)+        <|> Pi "_" <$> expr2 <*> (match Lexer.Arrow *> expr1)+        <|> Family <$> types <*> (match Lexer.In *> expr1)+        <|> Lets <$> lets <*> (match Lexer.In *> expr1)+        <|> expr2+        )++    vexpr <- rule+        (   V <$> label <*> (match Lexer.At *> number)+        <|> V <$> label <*> pure 0+        )++    expr2 <- rule+        (   App <$> expr2 <*> expr3+        <|> expr3+        )++    let makeExpr3 p =+            (   Var <$> vexpr+            <|> match Lexer.Star *> pure (Const Star)+            <|> match Lexer.Box  *> pure (Const Box )+            <|> Embed <$> embed+            <|> (Natural . fromIntegral) <$> number+            <|>     List+                <$> (match Lexer.OpenList *> expr0)+                <*> (many (match Lexer.Comma *> expr0) <* match Lexer.CloseBracket)+            <|>     Path+                <$> (match Lexer.OpenPath *> expr0)+                <*> many ((,) <$> object <*> expr0)+                <*> (object <* match Lexer.CloseBracket)+            <|>     Do+                <$> (match Lexer.Do *> expr0)+                <*> (match Lexer.OpenBrace *> many bind)+                <*> (bind <* match Lexer.CloseBrace)+            <|> (match Lexer.OpenParen *> p <* match Lexer.CloseParen)+            )++    expr3  <- rule (makeExpr3 expr0)+    expr3' <- rule (makeExpr3 expr1)++    arg <- rule+        (       Arg+            <$> (match Lexer.OpenParen *> label)+            <*> (match Lexer.Colon *> expr1 <* match Lexer.CloseParen)+        <|>     Arg "_" <$> expr3'+        )++    args <- rule (many arg)++    data_ <- rule (Data <$> (match Lexer.Data *> label) <*> args)++    datas <- rule (many data_)++    type_ <- rule+        (       Type+            <$> (match Lexer.Type *> label)+            <*> datas+            <*> (match Lexer.Fold *> label)+        <|>     Type+            <$> (match Lexer.Type *> label)+            <*> datas+            <*> pure "_"+        )++    types <- rule (some type_)++    let_ <- rule+        (   Let+        <$> (match Lexer.Let *> label)+        <*> args+        <*> (match Lexer.Colon *> expr0)+        <*> (match Lexer.Equals *> expr1)+        )++    lets <- rule (some let_)++    object <- rule (match Lexer.OpenBrace *> expr0 <* match Lexer.CloseBrace)++    bind <- rule+        (   (\x y z -> Bind (Arg x y) z)+        <$> label+        <*> (match Lexer.Colon *> expr0)+        <*> (match Lexer.LArrow *> expr0 <* match Lexer.Semicolon)+        )++    embed <- rule+        (   File <$> file+        <|> URL <$> url+        )++    return (expr0, types)++-- | The specific parsing error+data ParseMessage+    -- | Lexing failed, returning the remainder of the text+    = Lexing Text+    -- | Parsing failed, returning the invalid token and the expected tokens+    | Parsing Token [Token]+    deriving (Show)++-- | Structured type for parsing errors+data ParseError = ParseError+    { position     :: Position+    , parseMessage :: ParseMessage+    } deriving (Typeable)++instance Show ParseError where+    show = Text.unpack . toLazyText . build++instance Exception ParseError++instance Buildable ParseError where+    build (ParseError (Lexer.P l c) e) =+            "\n"+        <>  "Line:   " <> build l <> "\n"+        <>  "Column: " <> build c <> "\n"+        <>  "\n"+        <>  case e of+            Lexing r                                     ->+                    "Lexing: \"" <> build remainder <> dots <> "\"\n"+                <>  "\n"+                <>  "Error: Lexing failed\n"+              where+                remainder = Text.takeWhile (/= '\n') (Text.take 64 r)+                dots      = if Text.length r > 64 then "..." else mempty+            Parsing t ts ->+                    "Parsing : " <> build (show t ) <> "\n"+                <>  "Expected: " <> build (show ts) <> "\n"+                <>  "\n"+                <>  "Error: Parsing failed\n"++runParser+    :: (forall r . Grammar r (Prod r Token LocatedToken a))+    -> Text+    -> Either ParseError a+runParser p text = evalState (runExceptT m) (Lexer.P 1 0)+  where+    m = do+        (locatedTokens, mtxt) <- lift (Pipes.toListM' (Lexer.lexExpr text))+        case mtxt of+            Nothing  -> return ()+            Just txt -> do+                pos <- lift get+                throwE (ParseError pos (Lexing txt))+        let (parses, Report _ needed found) =+                fullParses (parser p) locatedTokens+        case parses of+            parse:_ -> return parse+            []      -> do+                let LocatedToken t pos = case found of+                        lt:_ -> lt+                        _    -> LocatedToken Lexer.EOF (Lexer.P 0 0)+                throwE (ParseError pos (Parsing t needed))++-- | Parse an `Expr` from `Text` or return a `ParseError` if parsing fails+exprFromText :: Text -> Either ParseError Expr+exprFromText = runParser (fmap fst expr)++{-| Parse a type definition from `Text` or return a `ParseError` if parsing+    fails+-}+typesFromText :: Text -> Either ParseError [Type]+typesFromText = runParser (fmap snd expr)
+ src/Annah/Tutorial.hs view
@@ -0,0 +1,1699 @@+{-| Annah is a tiny language that serves to illustrate how various programming+    constructs can be desugared to lambda calculus.  The most sophisticated+    feature that Annah supports is desugaring mutually recursive datatypes+    to non-recursive lambda expressions.++    Annah is not intended to be used as a production language.  Rather, Annah is+    a step along the way towards a production language that I factored out as+    a reusable library that others can learn from and possibly fork for their+    own use cases.++    Under the hood, all Annah expressions are translated to a minimalist+    implementation of the calculus of constructions called Morte, which only+    supports non-recursive lambda expressions and their types.  You can find+    the Morte compiler and library here:++    <http://hackage.haskell.org/package/morte>++    Annah piggybacks on Morte meaning all Annah expressions are translated to+    Morte expressions and then those Morte expressions are type-checked and+    evaluated.  You cannot directly type-check or evaluate Annah expressions;+    you have to desugar them to Morte expressions first before you can do+    anything else with them.++    Annah is not very user-friendly (and I apologize for that!).  For example,+    Annah reuses Morte's type-checker which means that error messages are in+    terms of low-level lambda calculus expressions and not in terms of the+    original Annah source code.+  +    Most notably, Annah does not provide support for text, due to the gross+    inefficiency of encoding even basic ASCII text in lambda calculus.  Text+    handling would be better served by a backend with primitive support for+    text literals and operations on text.++    This tutorial assumes that you have first read the Morte tutorial, which+    you can find here:++    <http://hackage.haskell.org/package/morte/docs/Morte-Tutorial.html>++    Annah is a superset of Morte that implements many of the higher-level+    constructs mentioned in the Morte tutorial, which is why you should not skip+    reading the Morte tutorial.+-}++module Annah.Tutorial (+    -- * Introduction+    -- $introduction++    -- * Let+    -- $let++    -- * Data types+    -- $datatypes++    -- * Imports+    -- $imports++    -- * Autogenerate Types+    -- $types++    -- * Folds+    -- $folds++    -- * Recursive types+    -- $recursive++    -- * Prelude+    -- $prelude++    -- * Natural numbers+    -- $nats++    -- * Lists+    -- $lists++    -- * Monoids+    -- $monoids++    -- * Commands+    -- $commands++    -- * IO+    -- $io++    -- * Paths+    -- $paths++    -- * Conclusion+    -- $conclusion+    ) where++{- $introduction+    This library comes with a binary executable that you can use to compile+    Annah expressions to Morte expressions.  This executable can be used in two+    separate ways.++    First, you can read an Annah expression from standard input and the program+    will output the equivalent low-level Morte expression to standard output:++> $ annah+> type Bool+> data True+> data False+> fold if+> in                                                   +>     +> let not (b : Bool) : Bool = if b Bool False True+> in  not False+> <Ctrl-D>+> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++    Second, you can read an Annah expression in from a file if you provide the+    file name on the command line using the @compile@ subcommand:++> $ cat example.annah+> type Bool+> data True+> data False+> fold if+> in                                                   +>     +> let not (b : Bool) : Bool = if b Bool False True+> in  not False++> $ annah compile example.annah+> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++    Annah is a superset of Morte, so any Morte expression is also a valid Annah+    expression:++> $ annah+> \(a : *) -> \(x : a) -> x+> <Ctrl-D>+> λ(a : *) → λ(x : a) → x++    Like Morte, Annah is an explicitly typed language (i.e. no type inference).+-}++{- $let+    Annah supports let expressions which can be used to introduce functions and+    values.  For example, this is how you can define the polymorphic identity+    function in Annah:++> $ annah+> let id (a : *) (x : a) : a = x+> in  id+> <Ctrl-D>+> λ(a : *) → λ(x : a) → x++    You can define more than one thing in a let expression as long as you+    prefix each definition with @let@:++> $ annah+> let id (a : *) (x : a) : a = x  +> let const (a : *) (b : *) (x : a) (y : b) : a = x+> in  id+> <Ctrl-D>+> λ(a : *) → λ(x : a) → x++    The general form of a @let@ expression is:++> let f0 (x00 : _A00) (x01 : _A01) ... (x0j : _A0j) _B0 = b0+> let f1 (x10 : _A10) (x11 : _A11) ... (x1j : _A1j) _B1 = b1+> ...+> let fi (xi0 : _Ai0) (xi1 : _Ai1) ... (xij : _Aij) _Bi = bi+> in  e++    The above let expression desugars to the following lambda expression:++> (   λ(f0 : ∀(x00 : _A00) → ∀(x01 : _A01) → ... → ∀(x0j : _A0j) → _B0)+> →   λ(f1 : ∀(x10 : _A10) → ∀(x11 : _A11) → ... → ∀(x1j : _A1j) → _B1)+> →   ...+> →   λ(fi : ∀(xi0 : _Ai0) → ∀(xi1 : _Ai1) → ... → ∀(xij : _Aij) → _Bi)+> →   e+> )+> +> (λ(x00 : _A00) → λ(x01 : _A01) → ... → λ(x0j : _A0j) → b0)+> (λ(x10 : _A10) → λ(x11 : _A11) → ... → λ(x1j : _A1j) → b1)+> ...+> (λ(xi0 : _Ai0) → λ(xi1 : _Ai1) → ... → λ(xij : _Aij) → bi)++    The above @\'e\'@  is the \"body\" of the let expression and @f0@ through+    @fi@ are the \"let-bound terms\".  Due to the above translation, each+    \"let-bound\" term is only in scope for the \"body\" of the let-expression+    and the types of subsequent \"let-bound\" terms.++    To give a concrete example, our original @id@+@const@ let expression:++> let id (a : *) (x : a) : a = x  +> let const (a : *) (b : *) (x : a) (y : b) : a = x+> in  id++    ... was equivalent to:++> (   λ(id : ∀(a : *) → ∀(x : a) → a)+> →   λ(const : ∀(a : *) → ∀(b : *) → ∀(x : a) → ∀(y : b) → a+> →   id+> )+>+> (λ(a : *) → λ(x : a) → x)+> (λ(a : *) → λ(b : *) → λ(x : a) → λ(y : b) → x)++    ... which normalizes to:++> λ(a : *) → λ(x : a) → x++    The definition of @const@ is dead code that is optimized away by β-reduction+    because the let-bound @const@ term is never used within the body of the let+    expression.+-}++{- $datatypes+    Annah lets you define datatypes that scope over an expression.  For example,+    if you write:++> type Bool+> data True+> data False+> fold if+> in e++    ... then within the expression @\'e\'@ you will be able to use the @Bool@+    type, the @True@ and @False@ values, and the @if@ fold.++    The above definition of @Bool@ desugars to the following @let@ expression:++> let Bool  : *    = ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> let True  : Bool = λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True+> let False : Bool = λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False+> let if : Bool → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool =+>     λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x+> in  e++    ... which in turn desugars to:++> (   λ(Bool : *)+> →   λ(True : Bool)+> →   λ(False : Bool)+> →   λ(if : Bool → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool)+> →   e+> )+> +> (∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool)+> (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True)+> (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False)+> (λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x)++    Annah also supports recursive datatypes.  For example, you can define+    natural numbers like this:++> $ annah+> type Nat+> data Succ (pred : Nat)+> data Zero+> in   Succ (Succ (Succ Zero))+> <Ctrl-D>+> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    Notice how we can omit the @fold@ line, which is optional.++    You can also omit field names, too, and this code is also valid:++> $ annah+> type Nat+> data Succ Nat+> data Zero+> in   Succ (Succ (Succ Zero))+> λ(Nat : *) → λ(Succ : Nat → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    Field names are just used to give nicer names to bound variables in the+    desugared datatype definition and field names default to @\'_\'@ if you omit+    the name.++    You can find out how any given type or constructor is encoded by just+    returning the constructor as the result of the let expression:++> $ annah+> type Nat+> data Succ (pred : Nat)+> data Zero+> in   Succ+> λ(pred : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (pred Nat Succ Zero)++-}++{- $imports+    Annah supports imports using the same syntax as Morte but you may only+    import Morte expressions (/not/ Annah expressions).  You can embed a file+    path or http URL anywhere within an expression and Annah will substitute in+    the Morte expression (encoded as plain text) located at that path or URL.++    The reason Annah does not support importing Annah expressions is that Annah+    does not actually resolve the imports.  Annah piggybacks off of Morte's+    support for imports, and Morte only supports importing Morte expressions.++    Imports are extremely useful when combined with datatypes because you can+    create a separate file for each type and constructor of a datatype.  To+    illustrate this we'll manually encode @Bool@, @True@, @False@, and @if@ as+    separate Annah files (and later we will see how we can auto-generate these+    files):++> $ cat Bool.annah+> type Bool+> data True+> data False+> fold if+> in   Bool++> $ cat True.annah+> type Bool+> data True+> data False+> fold if+> in   True++> $ cat False.annah+> type Bool+> data True+> data False+> fold if+> in   False++> $ cat if.annah+> type Bool+> data True+> data False+> fold if+> in   if++    Then we will translate each of them to a file encoding the equivalent Morte+    expression without the @\".annah\"@ file suffix:++> $ annah compile  Bool.annah >  Bool+> $ annah compile  True.annah >  True+> $ annah compile False.annah > False+> $ annah compile    if.annah >    if++    Now that we've created a file for each type and term we can import them+    within other expressions.  For example, now we can define the @not@ function+    in terms of imported types and values:++> $ cat not.annah+> let not (b : ./Bool ) : ./Bool = ./if b ./Bool ./False ./True+> in  not++    Don't worry if you don't understand what the above expression means just+    yet.  This tutorial will explain what the right-hand side means in the+    section on \"Folds\".++    We can run this file through Annah, which will desugar and normalize the+    expression, but will preserve the original imports:++> $ annah compile not.annah > not+> $ cat not+> λ(b : ./Bool ) → ./if  b ./Bool  ./False  ./True++    Annah actually does resolve the imports for the purposes of type-checking+    the expression, but deliberately does not resolve the imports for the final+    normalized expression.  Annah does this to keep the expression \"dynamically+    linked\" so that the expression can continue to reflect changes to+    dependencies.++    If you prefer to statically link the expression then you can use Morte:++> $ echo "./not" | morte+> ∀(b : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(b : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → b (∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False) (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True)++    ... and you can also expand derived expressions, too:++> $ morte+> ./not ./True+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False++    ... desugaring them with Annah if necessary:++> $ annah | morte+> let doubleNegate (b : ./Bool ) : /Bool = ./not (./not b)+> in  doubleNegate ./True+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+>+> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++-}++{- $types+    Creating one file per type, fold, and data constructor gets tedious pretty+    quickly, so the @annah@ executable provides a convenient subcommand named+    @types@ for auto-generating these files.++    Just run the @annah types@ command and provide a datatype definition on+    standard input:++> $ annah types+> type Bool+> data True+> data False+> fold if+> <Ctrl-D>++    ... and @annah@ will create one directory for each type in the datatype+    definition:++> $ ls+> Bool/  Bool.annah++    Each type's directory will have two files per data constructor associated+    with the type and two files for the @fold@, too:++> $ ls Bool+> @  False  False.annah  if  if.annah  True  True.annah++    Everything comes in two flavors: the original Annah code and the equivalent+    Morte code:++> $ cat Bool/True.annah +> type Bool+> data True+> data False+> fold if+> in   True+> $ cat Bool/True+> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++    The Morte code for the type is located as a file named @\@@ underneath the+    type's directory:++> $ cat Bool.annah+> type Bool+> data True+> data False+> fold if+> in   Bool+> $ cat Bool/@+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool++    This is because Morte supports importing the directory by name if there is a+    file named @\@@ underneath the directory.  So, for example if you import+    @./Bool@ and it's a directory then Morte will import @.\/Bool\/\@@ instead:++> $ morte+> ./Bool+> <Ctrl-D>+> *+> +> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+-}++{- $folds+    Every datatype definition comes with an optional @fold@ which you can use to+    pattern match on a value of that type.  You can see what arguments the+    pattern match expects just by querying the type of the fold:++> $ morte+> ./Bool/if+> <Ctrl-D>+> ∀(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x++    ... and we can use imports to simplify the type to:++> ∀(x : ./Bool ) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool++    This type says that @if@ expects the following arguments:++    * A value named @x@ of type @./Bool@ to pattern match on (like+      @.\/Bool\/True@ or @.\/Bool\/False@)+    * The type of the result for each branch of the pattern match+    * The result to return if our value equals @.\/Bool\/True@+    * The result to return if our value equals @.\/Bool\/False@++    Carefully note that the second argument is named @Bool@ but can actually be+    any type.  Similarly, the third and fourth arguments are named after the+    @True@ and @False@ constructors but they actually represent how to handle+    each branch of the pattern match.++    So, for example, when we write:++> let not (b : ./Bool ) : ./Bool = ./if b ./Bool ./False ./True+> in  not++    ... it's as if we wrote the following Haskell code using pattern matching:++> let not :: Bool -> Bool+>     not b = case b of+>             True  -> False+>             False -> True+> in  not++    We could even format our code to parallel the layout of a Haskell pattern+    match:++> let not (b : ./Bool ) : ./Bool =+>     ./if b ./Bool+>     ./False+>     ./True+> in  not++    The only difference is that in the Annah code we have to explicitly supply+    the expected type of the result after the value that we pattern match on+    (i.e. the @./Bool@ immediately after the @./if b@).++    Our @./not@ function technically did not need to use the @./if@ @fold@.  For+    example, we could instead write:++> $ cat not.annah+> let not (b : ./Bool ) : ./Bool = b ./Bool ./False ./True+> in  not++    The @./if@ was unnecessary because it was just the identity function on+    @./Bool@s:++> $ cat if+> λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x++    .. which is the same as:++> λ(x : ./Bool ) → x++    The reason we can omit the @if@ is that all values of type @./Bool@ are+    already preformed pattern matches.  We can prove this to ourselves by+    consulting the definitions of @.\/Bool\/True@ and @.\/Bool\/False@:++> $ morte < ./Bool/True+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True+> $ morte < ./Bool/False+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False++    In other words, @.\/Bool\/True@ is just a preformed pattern match that+    always returns the first branch that you supply.  Vice versa,+    @.\/Bool\/False@ is just a preformed pattern match that always returns the+    second branch that you supply.++    In fact, all @fold@s are optional when you save a type and associated data+    constructors as separate files.  The only time we truly require the @fold@+    is when we pattern match on the type within the "body" of a datatype+    expression, like in our very first example:++> type Bool+> data True+> data False+> fold if+> in -- Everything below here is the "body" of the `Bool` datatype definition+>+> let not (b : Bool) : Bool = if b Bool False True+> in  not False++    @Bool@ and @./Bool@ are not the same type within the "body" of the @Bool@+    datatype definition.  If you omit the @if@ then you will get the following+    type error:++> $ annah+> type Bool+> data True+> data False+> fold if+> in+> +> let not (b : Bool) : Bool = b Bool False True+> in  not False+> <Ctrl-D>+> annah: +> Context:+> Bool : *+> True : Bool+> False : Bool+> if : ∀(x : Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> b : Bool+> +> Expression: b Bool+> +> Error: Only functions may be applied to values++    The @Context@ the compiler prints in the error message shows that the+    type-checker views the @Bool@ type as abstract and not the type of a+    pattern match.  However, the same @Context@ says that @if@ has the correct+    type to convert between the abstract @Bool@ type and the type we expect for+    a pattern match:++> if : ∀(x : Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool++    ... which we can simplify to just:++> -- The type of the bound variable named `if`+> if : ∀(x : Bool) → ./Bool++    In other words, @Bool@ and @./Bool@ are different types from the type+    checker's point of view.  That is why you must explicitly convert from+    @Bool@ to @./Bool@ using @if@ while inside that context.++    However, once you save @./Bool@, @./True@, @./False@ and @./if@ to separate+    files the distinction between @Bool@ and @./Bool@ vanishes.  The type of+    @./if@ (the file) is not the same as the type of @if@ (the bound variable):++> -- The type of the file named `./if`+> ./if : ∀(x : ./Bool ) → ./Bool++    You can deduce why the distinction disappears when you save things to+    separate files if you desugar the datatype definitions.  For example our+    @if.annah@ file was defined as:++> type Bool+> data True+> data False+> fold if+> in   if++    We can use the @annah desugar@ subcommand to see what that code desugars to+    before normalization:++> $ annah desugar < ./Bool/if.annah+> (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → λ(if : ∀(x : Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → if) (∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True) (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False) (λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x)++    ... which we can clean up a bit to get:++> (   λ(Bool : *)+> →   λ(True : Bool)+> →   λ(False : Bool)+> →   λ(if : Bool → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool)+> →   if+> )+> +> (∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool)+> (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True)+> (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False)+> (λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x)++    That then normalizes to;++> $ annah desugar < ./Bool/if.annah | morte+> ∀(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(x : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → x++    There is also another use for storing @fold@s as files and using them, even+    if they are not immediately necessary.  Saving a @fold@ to a file lets you+    provide a stable interface for pattern matching on a value if you ever+    want to change the internal implementation of a type without breaking+    backwards compatibility.++    For example, suppose that a user writes the following @not@ function using+    @./if@:++> let not (b : ./Bool ) : ./Bool = ./if b ./Bool ./False ./True+> in  not++    ... but we later decide we want to flip the order of of the @True@ and+    @False@ constructors in our datatype definition:++> $ annah types+> type Bool+> data False+> data True++    The above changes would break the user's code unless we change @./if@ to+    export the pattern match order that the user expects:++> $ cat > if+>     \(b : ./Bool )+> ->  \(Bool : *)+> ->  \(True : Bool)+> ->  \(False : Bool)+> ->  b Bool False True+> <Ctrl-D>++    Now the user's code continues to work as if nothing ever happened.++    So saving @fold@s to files and using them to pattern match is not strictly+    necessary, but if you do use them then you can change the underlying+    implementation of the type without breaking backwards compatibility.++    There's no way that you can force users to use the @fold@ that you provide+    since all saved expressions are encoded in lambda calculus, which does not+    provide any support for implementation hiding or encapsulation.  The best+    you can do is to simply warn users that you might break their code some+    day if they perform a \"raw pattern match\" (i.e. a pattern match without+    the use of a saved @fold@).+-}++{- $recursive+    Annah supports recursive and mutually recursive types.  We saw an example+    of recursive types with natural numbers:++> $ annah+> type Nat+> data Succ (pred : Nat)+> data Zero+> fold foldNat+>+> in   Succ (Succ (Succ Zero))+> <Ctrl-D>+> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    What might not be obvious is that if you save each type and constructor to+    a separate file then you can build a natural number just from the files.++    To illustrate this, we will compile our datatype definition to separate+    files:++> $ annah types+> type Nat+> data Succ (pred : Nat)+> data Zero+> fold foldNat+> <Ctrl-D>++    ... and now we can build natural numbers using these files:++> $ morte+> ./Nat/Succ (./Nat/Succ (./Nat/Succ ./Nat/Zero ))+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    This gives the exact same result as before, but now we are programming+    directly at the "top level" using files instead of programming inside the+    body of a datatype definition.++    We can also fold natural numbers using our @.\/Nat\/foldNat@ function.+    Let's consult the type of the function:++> ∀(x : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(x : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → x++    If we clean up that type we get:++>     ∀(x : ./Nat )+> →   ∀(Nat : *)+> →   ∀(Succ : ∀(pred : Nat) → Nat)+> →   ∀(Zero : Nat)+> →   Nat++    Conceptually, when we fold a @./Nat@ value using @.\/Nat\/foldNat@ we just+    replace each @.\/Nat\/Succ@ constructor with the argument of the fold+    labeled @Succ@ (i.e. the third argument).  Similarly, we substitute each+    @.\/Nat\/Zero@ constructor with the fourth argument labeled @Zero@.++    We also supply a type parameter named @Nat@ as the second argument.  This+    type parameter must match the input and output of whatever we use to replace+    the @.\/Nat\/Succ@ and @.\/Nat\/Zero@.++    For example, suppose that we wanted to write a function to test if a @./Nat@+    was an even number.  We would just substitute every @Zero@ constructor with+    @.\/Bool\/True@ and substitute every @.\/Nat\/Succ@ constructor with+    @./not@.  The code for that would be:++> $ cat not.annah  # Update `not.annah` to use our new file layout+> let not (b : ./Bool ) : ./Bool =+>     ./Bool/if b ./Bool+>         ./Bool/False+>         ./Bool/True+> in  not++> $ cat isEven.annah +> let isEven (n : ./Nat ) : ./Bool =+>     ./Nat/foldNat n ./Bool+>         ./not       -- Replace every `./Nat/Succ` with `./not`+>         ./Bool/True -- Replace every `./Nat/Zero` with `./Bool/True`+> in  isEven++    The let definitions are not strictly necessary since we could just write:++> $ cat not.annah+> \(b : ./Bool ) ->+>     ./Bool/if b ./Bool+>         ./Bool/False+>         ./Bool/True++> $ cat isEven.annah+> \(n : ./Nat ) ->+>     ./Nat/foldNat n ./Bool+>         ./not+>         ./Bool/True++    ... but the let definitions help the readability of the code by naming the+    functions and documenting their expected return types.++    Then we can compile our Annah expression to Morte code:++> $ annah compile    not.annah > not+> $ annah compile isEven.annah > isEven++    ... and test that @./isEven@ works:++> $ morte+> ./isEven (./Nat/Succ (./Nat/Succ ./Nat/Zero ))+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++    It works!  The result is identical to @.\/Bool\/True@:++> $ morte+> ./Bool/True+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+>+> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True++    Conceptually, what happened was that @./isEven@ just performed the+    desired substitutions, replacing every @.\/Nat\/Succ@ with @./not@ and+    replacing every @.\/Nat\/Zero@ with @.\/Bool\/True@:++> ./isEven (./Nat/Succ (./Nat/Succ ./Nat/Zero ))+>+> -- Constructor substitution+> = ./not (./not ./Bool/True )+>+> -- β-reduce+> = ./Bool/True++    Note that this is not really the path the compiler takes under the hood, but+    it's equivalent.++    We can also encode mutually recursive types such as the following type+    declaration for even and odd numbers:++> $ annah+> type Even+> data SuccE (predE : Odd)+> data ZeroE+> fold foldEven+> +> type Odd+> data SuccO (predO : Even)+> fold foldOdd+> +> in SuccE (SuccO ZeroE)+> λ(Even : *) → λ(Odd : *) → λ(SuccE : ∀(predE : Odd) → Even) → λ(ZeroE : Even) → λ(SuccO : ∀(predO : Even) → Odd) → SuccE (SuccO ZeroE)++    Like before, we can encode each type and term separately as files and the+    files:++> annah types+> type Even+> data SuccE (predE : Odd)+> data ZeroE+> fold foldEven+> +> type Odd+> data SuccO (predO : Even)+> fold foldOdd+> <Ctrl-D>++    ... and now these files can be used to build @./Even@ or @./Odd@ values:++> $ morte+> ./Even/SuccE (./Odd/SuccO ./Even/ZeroE )+> <Ctrl-D>+> ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Even+> +> λ(Even : *) → λ(Odd : *) → λ(SuccE : ∀(predE : Odd) → Even) → λ(ZeroE : Even) → λ(SuccO : ∀(predO : Even) → Odd) → SuccE (SuccO ZeroE)++    We can also consume mutually recursive types just by folding them.  Each+    type is already a preformed fold and we can consult each type's respective+    @fold@ function to see what arguments the @fold@ expects:++> $ morte+> ./Even/foldEven+> <Ctrl-D>+> ∀(x : ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Even) → ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Even+> +> λ(x : ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Even) → x++> $ morte+> ./Odd/foldOdd+> ∀(x : ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Odd) → ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Odd+> +> λ(x : ∀(Even : *) → ∀(Odd : *) → ∀(SuccE : ∀(predE : Odd) → Even) → ∀(ZeroE : Even) → ∀(SuccO : ∀(predO : Even) → Odd) → Odd) → x++    If we clean up the type of the @.\/Even\/foldEven@ function we get this:++>     ∀(x : ./Even )+> →   ∀(Even : *)+> →   ∀(Odd : *)+> →   ∀(SuccE : ∀(predE : Odd) → Even)+> →   ∀(ZeroE : Even)+> →   ∀(SuccO : ∀(predO : Even) → Odd)+> →   Even++    Conceptually, when we fold an @./Even@ value using @.\/Even\/foldEven@ we+    just replace each @.\/Even\/SuccE@ constructor with the argument of the fold+    labeled @SuccE@ (i.e. the fourth argument).  Similarly, we substitute each+    @.\/Even\/ZeroE@ constructor with the fifth argument named @ZeroE@ and+    substitute each @.\/Odd\/SuccO@ constructor with the sixth argument named+    @SuccO@.++    We also supply two type parameters named @Even@ and @Odd@.  These type+    parameters must match the input and output of whatever we use to replace+    the @SuccE@, @ZeroE@ and @SuccO@ constructors.++    For example, suppose that we wanted to write a function that converts an+    @./Even@ value to a @./Nat@.  We would just replace every @.\/Even\/SuccE@+    and @.\/Odd\/SuccO@ constructor with @Succ@ and replace every+    @.\/Even\/ZeroE@ constructor with @Zero@, like this:++> $ cat evenToNat.annah+> let evenToNat (e : ./Even ) : ./Nat =+>     ./Even/foldEven e ./Nat ./Nat+>         ./Nat/Succ  -- Replace every `./Even/SuccE` with `Succ`+>         ./Nat/Zero  -- Replace every `./Even/ZeroE` with `Zero`+>         ./Nat/Succ  -- Replace every `./Odd/SuccO`  with `Succ`+> in  evenToNat++    Now we can \"compile\" our @evenToNat@ function to Morte code:++> annah evenToNat.annah > evenToNat++    ... and test that it correctly converts @./Even@ values to their+    equivalent @./Nat@ values:++> $ morte+> ./evenToNat (./Even/SuccE (./Odd/SuccO ./Even/ZeroE ))+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ Zero)++    It works!  We can began with the number two, encoded as an @./Even@ number+    and ended with two encoded as a @./Nat@.++    As before, the @./evenTonat@ function was just performing the desired+    substitution, replacing each @.\/Even\/SuccE@ and @.\/Odd\/SuccO@ with+    @.\/Nat\/Succ@ and replacing @.\/Odd\/ZeroE@ with @.\/Nat\/Zero@:++> ./evenToNat (./Even/SuccE (./Odd/SuccO ./Even/ZeroE ))+>+> -- Constructor substitution+> = ./Nat/Succ (./Nat/Succ ./Nat/Zero )++    Again, this is not the path the compiler takes under the hood, but it's+    equivalent.+-}++{- $prelude+    Annah also comes with a Prelude of utility types and terms.  This Prelude is+    hosted remotely here:++    <http://sigil.place/prelude/annah/1.0/>++    You can visit the above link to browse the Prelude and see what is+    available.++    There are several ways that you can use the Prelude.  The most direct+    approach is to use expressions from the Prelude directly by referencing+    their URLs, like this:++> $ morte+> http://sigil.place/prelude/annah/1.0/Nat/Succ+> (   http://sigil.place/prelude/annah/1.0/Nat/Succ+>     (   http://sigil.place/prelude/annah/1.0/Nat/Succ+>         http://sigil.place/prelude/annah/1.0/Nat/Zero+>     )+> )+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    ... or you can selectively \"alias\" remote references locally by creating+    local files that refer to the remote URLs:++> $ echo "http://sigil.place/prelude/annah/1.0/Nat/Succ" > Succ+> $ echo "http://sigil.place/prelude/annah/1.0/Nat/Zero" > Zero+> $ morte+> ./Succ (./Succ (./Succ ./Zero ))+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero))++    ... or you can \"import\" the entire Prelude into your current directory+    using @wget@:++> $ wget -np -r --cut-dirs=3 http://sigil.place/prelude/annah/1.0/+> $ cd sigil.place+> $ ls+> (->)            Defer.annah    List.annah    Path         Sum0.annah+> (->).annah      Eq             Maybe         Path.annah   Sum1+> Bool            Eq.annah       Maybe.annah   Prod0        Sum1.annah+> Bool.annah      Functor        Monad         Prod0.annah  Sum2+> Category        Functor.annah  Monad.annah   Prod1        Sum2.annah+> Category.annah  index.html     Monoid        Prod1.annah+> Cmd             IO             Monoid.annah  Prod2+> Cmd.annah       IO.annah       Nat           Prod2.annah+> Defer           List           Nat.annah     Sum0++    This tutorial will assume that you have imported the Prelude locally.++    The Prelude is organized according to the following rules:++    * Each type (like @./Bool@ or @./Nat@) is a top-level directory.  You can+      reference that type in your code by its directory+    * Each constructor of that type lives underneath the type's directory.  For+      example, @True@ is located underneath the @./Bool@ directory+    * Functions associated with each type are also located underneath the type's+      directory.  For example, the @length@ function is located underneath the+      @./List@ directory.+    * Every expression is provided as both the original Annah code (with a+      @*.annah@ suffix) and Morte code (with no suffix).  For example, you+      will find the @Monoid.annah@ file which was the Annah expression used to+      create the @Monoid@ file which is a Morte expression.++    In order to use an expression within Morte you must explicitly import the+    expression within the Morte code, like this:++> $ echo "./List/length" | morte  # Good+> ∀(a : *) → ∀(xs : ∀(List : *) → ∀(Cons : ∀(head : a) → ∀(tail : List) → List) → ∀(Nil : List) → List) → ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Nil : Nat) → Nat+> +> λ(a : *) → λ(xs : ∀(List : *) → ∀(Cons : ∀(head : a) → ∀(tail : List) → List) → ∀(Nil : List) → List) → λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → xs Nat (λ(_ : a) → Succ)++    Reading the expression through standard input will (usually) not work:++> $ morte < List/length  # Bad+> ../List: openFile: does not exist (No such file or directory)++    The reason why is that everything in the Prelude uses relative imports to+    reference each other.  This is what allows the Prelude to correctly+    function both when you reference the Prelude remotely and when you download+    the Prelude locally.  If you read the expression through standard input+    then Morte incorrectly concludes that any further imports are relative to+    your current directory.  However, if you explicitly import the expression+    within the code then Morte correctly concludes that transitive imports are+    relative to the imported file's path.++    For example, the @List/length@ file has the following contents:++> cat List/length+> λ(a : *) → λ(xs : ../List  a) → λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → xs Nat (λ(_ : a) → Succ)++    There is one relative reference within that file to @../List@.  That+    reference is relative to the current file's directory (i.e. relative to+    @List/@) which means that it still points to the same directory: @List@.  We+    could have also used just @.@ to refer to the current directory but that+    would be less readable.++    However, if you read in @List/length@ from standard input, then @morte@+    looks for @../List@ expression relative to your present working directory+    and fails.++    Annah's Prelude has some similarities to Haskell's standard libraries and+    some differences.  The rough correspondences are:++    * @(->)@ corresponds to Haskell's @(->)@ type constructor+    * @Bool@ corresponds to Haskell's `Bool` type+    * @Cmd@ corresponds to the operational monad (i.e.+      "Control.Monad.Operational".`Control.Monad.Operational.Program`)+    * @Defer@ corresponds to+      "Data.Functor.Coyoneda".`Data.Functor.Coyoneda.Coyoneda`+    * @List@ corresponds to Haskell lists except that Annah @List@s are always+      finite because they are encoded recursively+    * @Maybe@ corresponds to Haskell's `Maybe` type constructor+    * @Nat@ corresponds to Haskell's `Numeric.Natural.Natural` type, except+      much less efficient than its Haskell counterpart+    * @Path@ corresponds to a free category.  As far as I know there is no+      standard Haskell implementation for free categories to reference+    * @Prod0@ corresponds to Haskell's @()@ type.  Mnemonic: \"Product type with+      zero fields\"+    * @Prod1@ corresponds to Haskell's `Data.Functor.Identity` type constructor.+      Mnemonic: \"Product type with one field\"+    * @Prod2@ corresponds to Haskell's 2-tuple type constructor.  Mnemonic:+      \"Product type with two fields\"+    * @Sum0@ corresponds to Haskell's `Data.Void.Void` type.  Mnemonic: \"Sum+      type with zero fields\"+    * @Sum1@ also corresponds to Haskell's `Data.Functor.Identity` type+      constructor.  Mnemonic: \"Sum type with one field\"+    * @Sum2@ corresponds to Haskell's `Either` type constructor.  Mnemonic:+      \"Sum type with two fields\"+    * @IO@ corresponds to a very simple `IO` type constructor that only supports+      two operations:++      > ./IO/get : ./IO ./Nat+      > ./IO/put : ./Nat -> ./IO ./Prod0++    In addition to those types, Annah also encodes several of Haskell's type+    classes as values.  Neither Annah nor Morte supports type classes /per se/.+    Instead, each class is encoded as a type constructor and each instance is+    a term of the corresponding type:++    * @Functor@ corresponds to Haskell's `Functor` class+    * @Monoid@ corresponds to Haskell's `Data.Monoid.Monoid` class+    * @Monad@ corresponds to Haskell's `Monad` class+    * @Category@ corresponds to Haskell's `Control.Category.Category` class++    However, the specification of each type class radically differs from how+    Haskell encodes things.  We'll revisit this in a later section.+-}++{- $nats+    The Prelude provides addition and multiplication for natural numbers:++> $ cat > three+> ./Nat/Succ (./Nat/Succ (./Nat/Succ ./Nat/Zero ))+> <Ctrl-D>++> $ morte+> ./Nat/(+) ./three ./three+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Zero)))))++> $ morte+> ./Nat/(*) ./three ./three+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))++    Also, Annah provides basic syntactic support for natural number literals:++> $ annah | morte+> ./Nat/(+) 3 3+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Zero)))))++> $ annah | morte+> ./Nat/(*) 3 3+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))++-}++{- $lists+    The Prelude provides operations on lists, too:++> $ annah | morte+> ./List/replicate ./Bool 3 ./Bool/True+> <Ctrl-D>+> ∀(List : *) → ∀(Cons : ∀(head : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → ∀(tail : List) → List) → ∀(Nil : List) → List+> +> λ(List : *) → λ(Cons : ∀(head : ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool) → ∀(tail : List) → List) → λ(Nil : List) → Cons (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True) (Cons (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True) (Cons (λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → True) Nil))++    Annah also provides support for list literals:++> $ annah > bools+> [nil ./Bool , ./Bool/True , ./Bool/False , ./Bool/True ]+> <Ctrl-D>++> $ cat bools+> λ(List : *) → λ(Cons : ∀(head : ./Bool ) → ∀(tail : List) → List) → λ(Nil : List) → Cons ./Bool/True  (Cons ./Bool/False  (Cons ./Bool/True  Nil))++    The general format for lists is:++> [nil elementType, element0, element1, ..., elementN]++    Here are some examples of operations on lists:++> $ morte+> ./List/null ./Bool ./bools+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False++> $ morte+> ./List/length ./Bool (./List/(++) ./Bool ./bools ./bools )+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Nil : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Nil : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Nil)))))++> $ annah | morte+> \(a : *) -> \(xs : ./List a) -> ./List/(++) a xs [nil a]+> <Ctrl-D>+> ∀(a : *) → ∀(xs : ∀(List : *) → ∀(Cons : ∀(head : a) → ∀(tail : List) → List) → ∀(Nil : List) → List) → ∀(List : *) → ∀(Cons : a → List → List) → ∀(Nil : List) → List+> +> λ(a : *) → λ(xs : ∀(List : *) → ∀(Cons : ∀(head : a) → ∀(tail : List) → List) → ∀(Nil : List) → List) → xs++    The last example shows how @morte@ can optimized away @xs ++ []@ to just+    @xs@.+-}++{- $monoids+    Annah also provides several folds on lists, like @sum@ or @and@:++> $ annah | morte+> <Ctrl-D>+> ./Nat/sum [nil ./Nat , 1, 2, 3, 4]+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))++> $ annah | morte+> <Ctrl-D>+> ./Bool/and [nil ./Bool , ./Bool/True , ./Bool/False , ./Bool/True ]+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False++    What's interesting about these folds is their type:++> $ cat Nat/sum.annah+> let sum : ../Monoid ../Nat = \(xs : ../List ../Nat ) -> xs ../Nat ./(+) 0+> in  sum++> $ cat Bool/and.annah+> let and : ../Monoid ../Bool =+>     \(xs : ../List ../Bool ) -> xs ../Bool ./(&&) ./True+> in  and++    You might have been expecting their types to be something like this:++> sum : ../List ../Nat  -> ../Nat+> and : ../List ../Bool -> ../Bool++    ... and you would have been right because that is actually what their types+    are!  This is because of how @./Monoid.annah@ is defined:++> $ cat Monoid.annah+> let Monoid (m : *) : * = ./List m -> m+> in  Monoid++    In other words, a `Monoid` \"instance\" for a type @m@ is just a function+    that folds a @./List@ of @m@s into a single @m@.  The @./sum@ and @./and@+    functions that fold lists also double as @./Monoid@ instances.++    You can recover the traditional Haskell `Monoid` operations like `mempty`+    and `mappend` from the above @./Monoid@ definition:++> $ cat Monoid/mempty.annah+> let mempty (m : *) (monoid : ./Monoid m) : m =+>     monoid [nil m]+> in  mempty++> $ cat Monoid/mappend.annah+> let mappend (m : *) (monoid : ./Monoid m) (l : m) (r : m) : m =  +>     monoid [nil m, l, r]+> in  mappend++    For example:++> $ morte+> ./Monoid/mempty ./Nat ./Nat/sum+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Zero++> $ annah | morte+> ./Monoid/mappend ./Nat ./Nat/sum 4 5+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))++    However, in practice it's easier to just use the folds directly instead of+    using @.\/Monoid\/mempty@ or @.\/Monoid\/mappend@:++> $ annah | morte+> ./Nat/sum [nil ./Nat ]+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Zero++> $ annah | morte+> ./Nat/sum [nil ./Nat , 4, 5]+> <Ctrl-D>+> ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat+> +> λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))+-}++{- $commands+    Annah also provides syntactic support for chaining commands using @do@+    notation, in a style very similar to Haskell.  The following examples will+    all give very large outputs so I will tidy the output results, although+    there is not a good way to tidy the output in general:++    For example, here is how you write a list comprehension in Annah.++> $ annah | morte  # Output cleaned up by hand+> ./List/Monad ./Nat (do ./List {+>     x : ./Nat <- [nil ./Nat , 1, 2, 3];+>     y : ./Nat <- [nil ./Nat , 4, 5, 6];+>     _ : ./Nat <- ./List/pure ./Nat (./Nat/(+) x y);+> })+> <Ctrl-D>+>     ∀(List : *)+> →   ∀(Cons : ∀(head : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(tail : List) → List)+> →   ∀(Nil : List)+> →   List+> +>     λ(List : *)+> →   λ(Cons : ∀(head : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(tail : List) → List)+> →   λ(Nil : List)+> →   Cons+>     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ Zero)))))+>     (   Cons+>         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Zero))))))+>         (   Cons+>             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))+>             (   Cons+>                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Zero))))))+>                 (   Cons+>                     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))+>                     (   Cons+>                         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))+>                         (   Cons+>                             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))+>                             (   Cons+>                                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))+>                                 (   Cons+>                                     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))+>                                     Nil+>                                 )+>                             )+>                         )+>                     )+>                 )+>             )+>         )+>     )++    ... which is equivalent to:++> ./List ./Nat+>+> [nil ./Nat , 5, 6, 7, 6, 7, 8, 7, 8, 9]++    Annah @do@ notation has a few important differences from Haskell's @do@+    notation:++    * Every command's return type must be annotated; even the final command+    * Braces are required and semicolons are required on all lines+    * You must annotate the monad's type constructor right after the @do@+    * You (usually) wrap the @do@ block in the @./Monad@ instance for your+      type constructor followed by the @do@ block's return value++    Here is an example diagram to illustrate the last rule:++> +-- Monad instance for ./List+> |+> |            +-- The return value of block ...+> |            |+> v            v+> ./List/Monad ./Nat (do ./List {+>     x : ./Nat <- [nil ./Nat , 1, 2, 3];+>     y : ./Nat <- [nil ./Nat , 4, 5, 6];+>     _ : ./Nat <- ./List/pure ./Nat (./Nat/(+) x y);+> })      ^+>         |+>         +-- ... which must match this return value++    You actually don't have to wrap the @do@ block in a @./Monad@ instance, but+    you will get a different result.  Let's see what happens if we omit the+    @./Monad@ instance:++> $ annah | morte  # Output cleaned up by hand+> do ./List {+>     x : ./Nat <- [nil ./Nat , 1, 2, 3];+>     y : ./Nat <- [nil ./Nat , 4, 5, 6];+>     _ : ./Nat <- ./List/pure ./Nat (./Nat/(+) x y);+> }+> <Ctrl-D>+>     ∀(Cmd : *)+> →   ∀(Bind : ∀(b : *) → (∀(List : *) → ∀(Cons : ∀(head : b) → ∀(tail : List) → List) → ∀(Nil : List) → List) → (b → Cmd) → Cmd)+> →   ∀(Pure : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Cmd)+> →   Cmd+>+>     λ(Cmd : *)+> →   λ(Bind : ∀(b : *) → (∀(List : *) → ∀(Cons : ∀(head : b) → ∀(tail : List) → List) → ∀(Nil : List) → List) → (b → Cmd) → Cmd)+> →   λ(Pure : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Cmd)+> →   Bind+>     (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat)+>     (   λ(List : *)+>     →   λ(Cons : ∀(head : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(tail : List) → List)+>     →   λ(Nil : List)+>     →   Cons+>         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → Succ)+>         (   Cons+>             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ Zero))+>             (   Cons+>                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ Zero)))+>                 Nil+>             )+>         )+>     )+>     (   λ(x : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat)+>     →   Bind+>         (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat)+>         (   λ(List : *)+>         →   λ(Cons : ∀(head : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(tail : List) → List)+>         →   λ(Nil : List)+>         →   Cons+>             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>             (   Cons+>                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ Zero)))))+>                 (   Cons+>                     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ (Succ (Succ Zero))))))+>                     Nil+>                 )+>             )+>         )+>         (   λ(y : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat)+>         →   Bind+>             (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat)+>             (   λ(List : *)+>             →   λ(Cons : ∀(head : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → ∀(tail : List) → List)+>             →   Cons+>                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → x Nat Succ (y Nat Succ Zero))+>             )+>             Pure+>         )+>     )++    ... which is equivalent to:++> ./Cmd ./List./Nat+>+>     λ(Cmd : *)+> →   λ(Bind : ∀(b : *) → ./List b → (b → Cmd) → Cmd)+> →   λ(Pure : ./Nat → Cmd)+> →   Bind+>     ./Nat+>     [nil ./Nat , 1, 2, 3]+>     (   λ(x : ./Nat )+>     →   Bind+>         ./Nat+>         [nil ./Nat 4, 5, 6]+>         (   λ(y : ./Nat )+>         →   Bind+>             ./Nat+>             [nil ./Nat (./Nat/(+) x y)]+>             Pure+>         )+>     )++    The @do@ notation is desugaring to a data type named @./Cmd@ that inserts+    placeholders for each @<-@ (pronounced: \"bind\").  In the Haskell world+    this datatype is commonly known as the \"operational\" monad.++    So why did we wrap the @do@ block in @.\/List\/Monad@?  Well, let's check+    out the type of the @.\/List\/Monad@ function:++> $ cat ./List/Monad.annah +> let Monad: ../Monad ../List+>     =   \(a : *)+>     ->  \(m : ../Cmd ../List a)+>     ->  m (../List a) (\(b : *) -> ./(>>=) b a) (./pure a)+> in  Monad++    Hmmm, that's weird.  Wasn't it supposed to be a function?  Actually, it is!+    To see why, let's check out how @./Monad@ is defined:++> let Monad (m : * -> *) : * = forall (a : *) -> ./Cmd m a -> m a+> in  Monad++    A @./Monad m@ is a function that transforms a @./Cmd m a@ into an @m a@ by+    replacing each @Bind@ with the correct \"bind\" operation for that `Monad`+    and replaces each @Pure@ with the correct \"pure\" operation for that+    `Monad`.  Therefore a @./Monad ./List@ is a function that transforms a+    @.\/Cmd .\/List a@ into a @./List a@.++    That's why we wrap the @do@ block in @.\/List\/Monad@ because the @do@+    block starts out with this type:++> do ./List { ... } : ./Cmd ./List ./Nat++    ... and then when we apply the @.\/List\/Monad function we get back a+    bona-fide @./List@:++> ./List/Monad ./Nat (do ./List { ... }) ./List ./Nat++    There are a couple of parallels between Annah's @./Monad@+@./Cmd@ and+    Annah's @./Monoid@+@./List@:++    * Both of them have syntactic support for building a placeholder of some+      sort.  List notation builds a @./List@ and @do@ notation builds a @./Cmd@+    * Both of them have a way to fold the placeholder into a single value.+      @./Monoid@s fold @./List@s and @./Monad@s fold @./Cmd@s.++-}++{- $io++    Annah also supports a very simplistic @./IO@ type as a proof of concept for+    how you would model a foreign function interface.  For example, here is an+    @./IO@ action that reads a @./Nat@ and writes out the same @./Nat@:++> $ annah+> ./IO/Monad ./Prod0 (do ./IO {+>     n : ./Nat   <- ./IO/get  ;+>     _ : ./Prod0 <- ./IO/put n;+> })+> <Ctrl-D>+> ./IO/Monad  ./Prod0  (λ(Cmd : *) → λ(Bind : ∀(b : *) → ./IO  b → (b → Cmd) → Cmd) → λ(Pure : ./Prod0  → Cmd) → Bind ./Nat  ./IO/get  (λ(n : ./Nat ) → Bind ./Prod0  (./IO/put  n) Pure))++    Annah also provides utilities similar to Haskell for chaining commands, such+    as @.\/Monad\/replicateM_.annah@ which lets you repeat a command a fixed+    number of times:++> $ cat Monad/replicateM_.annah+> let replicateM_ (m : * -> *) (n : ../Nat ) (cmd : m ../Prod0 )+>   : ../Cmd m ../Prod0+>   = ./sequence_ m (../List/replicate (m ../Prod0 ) n cmd)+> in  replicateM_++    Notice that @.\/Monad\/replicateM_@ does not take a @./Monad@ instance as+    an argument.  Instead, @.\/Monad\/replicateM_@ returns a @./Cmd@ which+    you can fold with the appropriate @./Monad@ instance:++    For example:++> $ annah | morte  # Output cleaned up by hand+> ./IO/Monad ./Prod0 (./Monad/replicateM_ ./IO 10 (./IO/put 4))+>     ∀(IO : *)+> →   ∀(Get_ : ((∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO) → IO)+> →   ∀(Put_ : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO → IO)+> →   ∀(Pure_ : (∀(Prod0 : *) → ∀(Make : Prod0) → Prod0) → IO)+> →   IO+> +>     λ(IO : *)+> →   λ(Get_ : ((∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO) → IO)+> →   λ(Put_ : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO → IO)+> →   λ(Pure_ : (∀(Prod0 : *) → ∀(Make : Prod0) → Prod0) → IO)+> →   Put_+>     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>     (   Put_+>         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>         (   Put_+>             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>             (   Put_+>                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                 (   Put_+>                     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                     (   Put_+>                         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                         (   Put_+>                             (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                             (   Put_+>                                 (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                                 (   Put_+>                                     (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                                     (   Put_+>                                         (λ(Nat : *) → λ(Succ : ∀(pred : Nat) → Nat) → λ(Zero : Nat) → Succ (Succ (Succ (Succ Zero))))+>                                         (Pure_ (λ(Prod0 : *) → λ(Make : Prod0) → Make))+>                                     )+>                                 )+>                             )+>                         )+>                     )+>                 )+>             )+>         )+>     )++    If you clean that up a bit you get a syntax tree for printing @4@ 10 times:++>     λ(IO : *)+> →   λ(Get_ : (./Nat → IO) → IO)+> →   λ(Put_ : ./Nat → IO → IO)+> →   λ(Pure_ : ./Prod0 → IO)+> →   Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Put_ 4 (Pure_ ./Prod0/Make ))))))))))++    Let's try a more complicated program, that reads and writes integers 10+    times:++> $ annah | morte+> let io : ./IO ./Prod0 = ./IO/Monad ./Prod0 (do ./IO {+>     n : ./Nat   <- ./IO/get  ;+>     _ : ./Prod0 <- ./IO/put n;+> })+> in  ./IO/Monad ./Prod0 (./Monad/replicateM_ ./IO 10 io)+> <Ctrl-D>+> ∀(IO : *) → ∀(Get_ : ((∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO) → IO) → ∀(Put_ : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO → IO) → ∀(Pure_ : (∀(Prod0 : *) → ∀(Make : Prod0) → Prod0) → IO) → IO+> +> λ(IO : *) → λ(Get_ : ((∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO) → IO) → λ(Put_ : (∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → IO → IO) → λ(Pure_ : (∀(Prod0 : *) → ∀(Make : Prod0) → Prod0) → IO) → Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Get_ (λ(r : ∀(Nat : *) → ∀(Succ : ∀(pred : Nat) → Nat) → ∀(Zero : Nat) → Nat) → Put_ r (Pure_ (λ(Prod0 : *) → λ(Make : Prod0) → Make)))))))))))))))))))))++    ... which if we simplify we get:++>     λ(IO : *)+> →   λ(Get_ : (./Nat → IO) → IO)+> →   λ(Put_ : ./Nat → IO → IO)+> →   λ(Pure_ : ./Prod0 → IO)+> →   Get_ (λ(r : ./Nat ) →+>       Put_ r (+>         Get_ (λ(r : ./Nat ) →+>           Put_ r (+>             Get_ (λ(r : ./Nat ) →+>               Put_ r (+>                 Get_ (λ(r : ./Nat ) →+>                   Put_ r (+>                     Get_ (λ(r : ./Nat ) →+>                       Put_ r (+>                         Get_ (λ(r : ./Nat ) →+>                           Put_ r (+>                             Get_ (λ(r : ./Nat ) →+>                               Put_ r (+>                                 Get_ (λ(r : ./Nat ) →+>                                   Put_ r (+>                                     Get_ (λ(r : ./Nat ) →+>                                       Put_ r (+>                                         Get_ (λ(r : ./Nat ) →+>                                           Put_ r (+>                                             Pure_ ./Prod0/Make))))))))))))))))))))++    In other words, we've built an abstract syntax tree representing ten+    @Get_@ and @Put_@ nodes where each @Get_@ node threads its result to the+    next @Put_@ node.++    Annah cannot run this abstract syntax tree since Annah does not have a+    backend to interpret this tree.  The most Annah can do is model effects+    without running them.+-}++{- $paths+    Annah provides support for the `Category` type class, too, using an approach+    very similar to the support for `Monoid` and `Monad`:++    * Provide a placeholder type named @./Path@ (which is a \"free category\")+    * Provide syntactic support for building @./Path@s+    * Define a @./Category@ to be something that folds @./Path@s++> $ cat Category.annah+> let Category (cat : * -> * -> *) : * =+>     forall (a : *) -> forall (b : *) -> ./Path cat a b -> cat a b+> in  Category++    Here is an example of composing several functions using the @./Category@+    instance for functions:++> $ annah | morte+> let even (n : ./Nat ) : ./Bool = n ./Bool ./Bool/not ./Bool/True+>+> in  let f : ./List ./Nat -> ./Bool =+>     ./(->)/Category (./List ./Nat ) ./Bool+>         [id ./(->) { ./List ./Nat } ./Nat/sum { ./Nat } even { ./Bool } ./Bool/not { ./Bool }]+>+>     in  f [nil ./Nat , 1, 2, 3, 4+> <Ctrl-D>+> ∀(Bool : *) → ∀(True : Bool) → ∀(False : Bool) → Bool+> +> λ(Bool : *) → λ(True : Bool) → λ(False : Bool) → False++    The above code creates a composition chain of three functions, reading from+    left to right:++    * @.\/Nat/sum@, which has type @.\/List .\/Nat -> .\/Nat@+    * @even@, which has type @.\/Nat -> .\/Bool@+    * @.\/Bool\/not@, which has type @.\/Bool -> .\/Bool@++    Annah's path notation requires you to annotate the types along the way as+    you compose each component.  In the above example, you can find each+    function's input type immediately to the left of that function and the+    output type immediately to the right of each function.  Types are surrounded+    by braces to separate them from the things you compose.++    Annah's path notation differs from lists in a couple of ways:++    * You replace @nil@ with @id@+    * The @id@ is followed by the type constructor that you are chaining+    * You replace commas with intermediate types++    You may find the notation easier to read if you put each composable+    component on a separate line preceded by the corresponding input type:++> let even (n : ./Nat ) : ./Bool = n ./Bool ./Bool/not ./Bool/True+>+> in  let f : ./List ./Nat -> ./Bool =+>     ./(->)/Category (./List ./Nat ) ./Bool [id ./(->)+>         { ./List ./Nat } ./Nat/sum+>         { ./Nat        } even+>         { ./Bool       } ./Bool/not+>         { ./Bool       }+>     ]+>+>     in  f [nil ./Nat , 1, 2, 3, 4]++    Annah's Prelude only provides support for one @./Category@ instance for+    functions named @./(->)/Category@, so in practice the @./Category@ support+    is not that handy out-of-the box and is mainly provided for completeness.+-}++{- $conclusion+    Those are all the features that Annah supports!  Annah is a very tiny+    language and library that illustrates and implements basic idioms for+    translating functional programming concepts into pure lambda calculus.++    Hopefully you can use Annah to learn how to encode a subset of Haskell in a+    completely total programming language.  If you translate any Haskell+    functions to Annah you can contribute them upstream to the Annah prelude by+    submitting a pull request against the Annah repository:++    <https://github.com/Gabriel439/Haskell-Annah-Library/tree/master/Prelude>+-}