/- This is newt, a self-hosted, dependent typed programming language that compiles to javascript and borrows a lot of syntax from Idris and Agda. This page is a very simple web playground based on the codemirror editor. It runs newt in a web worker. Block comments follow Lean because they're easier to type on a US keyboard. -/ -- One-line comments begin with two hyphens -- every file begins with a `module` declaration -- it must match the filename module Tour -- We can import other modules, with a flat namespace and no cycles, -- diamonds are ok, Prelude is not imported by default, only explicitly -- imported modules are in scope -- commented out because we redefine parts of Prelude in this file. -- import Prelude -- We're calling the universe U and are doing type in type for now -- Inductive type definitions are similar to Idris, Agda, or Haskell data Nat : U where Z : Nat S : Nat -> Nat -- Nat-shaped data is turned into numbers in codegen. -- Multiple names are allowed on the left: data Bool : U where True False : Bool -- Enum shaped data becomes a bare string (the constructor name) in codegen. -- function definitions are equations using dependent pattern matching plus : Nat -> Nat -> Nat plus Z m = m plus (S n) m = S (plus n m) -- we can also have case statements on the right side -- the core language includes case statements -- here `\` is used for a lambda expression: plus' : Nat -> Nat -> Nat plus' = \ n m => case n of Z => m S n => S (plus' n m) -- We can define operators. Mixfix is supported, but we don't -- allow ambiguity (so you can't have both [_] and [_,_]). See -- the Reasoning.newt sample file for a mixfix example. infixl 2 _≡_ -- Here is an equality, like Idris, everything goes to the right of the colon -- Implicits are denoted with braces `{ }` -- unlike idris, you have to declare all of your implicits data _≡_ : {0 A : U} -> A -> A -> U where Refl : {0 A : U} {0 a : A} -> a ≡ a -- And now the compiler can verify that 1 + 1 = 2 test : plus (S Z) (S Z) ≡ S (S Z) test = Refl -- Ok now we do typeclasses. `class` and `instance` are sugar for -- ordinary data and functions: -- Let's say we want a generic `_+_` operator infixl 7 _+_ class Add a where _+_ : a -> a -> a instance Add Nat where Z + m = m (S n) + m = S (n + m) two : Nat two = S Z + S Z -- We can leave a hole in an expression with ? and the editor will show us the -- scope and expected type (hover to see) foo : Nat -> Nat -> Nat foo a b = ? -- Newt compiles to javascript, there is a tab to the right that shows the -- javascript output. There is some erasure, but inlining is not being done -- yet. -- We can define native types, if the type is left off, it defaults to U ptype SomePrimType : U -- The types Int, String, Char are special. Primitive numbers, strings, -- and characters inhabit them, respectively. We can match on primitives, but -- must provide a default case: isVowel : Char -> Bool isVowel 'a' = True isVowel 'e' = True isVowel 'i' = True isVowel 'o' = True isVowel 'u' = True isVowel _ = False -- And primitive functions have a type and a javascript definition: pfunc plusInt : Int -> Int -> Int := `(x,y) => x + y` pfunc plusString : String -> String -> String := `(x,y) => x + y` -- We can make them Plus instances: instance Add Int where _+_ = plusInt instance Add String where _+_ = plusString concat : String -> String -> String concat a b = a + b -- Now we define Monad class Monad (m : U -> U) where pure : ∀ a. a -> m a bind : ∀ a b. m a -> (a -> m b) -> m b /- This desugars to: data Monad : (m : U -> U) -> U where MkMonad : {m : U -> U} -> (pure : {a : _} -> a -> m a) -> (bind : {a : _} -> {b : _} -> m a -> a -> m b -> m b) -> Monad m pure : {m : U -> U} -> {{_ : Monad m}} -> {a : _} -> a -> m a pure {m} {{MkMonad pure bind}} = pure bind : {m : U -> U} -> {{_ : Monad m}} -> {a : _} -> {b : _} -> m a -> a -> m b -> m b bind {m} {{MkMonad pure bind}} = bind -/ -- we can declare multiple infix operators at once infixl 1 _>>=_ _>>_ _>>=_ : ∀ m a b. {{Monad m}} -> m a -> (a -> m b) -> m b _>>=_ ma amb = bind ma amb _>>_ : ∀ m a b. {{Monad m}} -> m a -> m b -> m b ma >> mb = ma >>= (λ _ => mb) -- Now we define list and show it is a monad. At the moment, I don't -- have sugar for Lists, infixr 3 _::_ data List : U -> U where Nil : ∀ A. List A _::_ : ∀ A. A -> List A -> List A infixr 7 _++_ _++_ : ∀ a. List a -> List a -> List a Nil ++ ys = ys (x :: xs) ++ ys = x :: (xs ++ ys) instance Monad List where pure a = a :: Nil bind Nil f = Nil bind (x :: xs) f = f x ++ bind xs f /- This desugars to: (the names in guillemots are not user-accessible) «Monad List,pure» : { a : U } -> a:0 -> List a:1 pure a = _::_ a Nil «Monad List,bind» : { a : U } -> { b : U } -> (List a) -> (a -> List b) -> List b bind Nil f = Nil bind (_::_ x xs) f = _++_ (f x) (bind xs f) «Monad List» : Monad List «Monad List» = MkMonad «Monad List,pure» «Monad List,bind» -/ -- We'll want Pair below. `,` has been left for use as an operator. -- Also we see that → can be used in lieu of -> infixr 1 _,_ _×_ data _×_ : U → U → U where _,_ : ∀ A B. A → B → A × B -- The _>>=_ operator is used for desugaring do blocks prod : ∀ A B. List A → List B → List (A × B) prod xs ys = do x <- xs y <- ys pure (x, y) data Unit = MkUnit ptype World data IORes a = MkIORes a World IO : U -> U IO a = World -> IORes a instance Monad IO where bind ma mab = \ w => case ma w of MkIORes a w => mab a w pure = MkIORes pfunc putStrLn uses (MkIORes MkUnit) : String -> IO Unit := `(s) => (w) => { console.log(s) return Prelude_MkIORes(null,Prelude_MkUnit,w) }` main : IO Unit main = putStrLn "Hello, World!"