Files
newt/playground/samples/Tour.newt
2025-07-18 20:47:45 -04:00

227 lines
5.7 KiB
Agda
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/-
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!"