1
Fork 0

Merged with typelevel-experiments

This commit is contained in:
Matei Adriel 2023-06-04 15:19:30 +02:00
parent 583484cab3
commit 62cee9bd63
12 changed files with 1118 additions and 0 deletions

10
typelevel/.gitignore vendored Normal file
View file

@ -0,0 +1,10 @@
/bower_components/
/node_modules/
/.pulp-cache/
/output/
/generated-docs/
/.psc-package/
/.psc*
/.purs*
/.psa*
/.spago

5
typelevel/.vscode/settings.json vendored Normal file
View file

@ -0,0 +1,5 @@
{
"[purescript]": {
"editor.formatOnSave": false
}
}

128
typelevel/packages.dhall Normal file
View file

@ -0,0 +1,128 @@
{-
Welcome to your new Dhall package-set!
Below are instructions for how to edit this file for most use
cases, so that you don't need to know Dhall to use it.
## Warning: Don't Move This Top-Level Comment!
Due to how `dhall format` currently works, this comment's
instructions cannot appear near corresponding sections below
because `dhall format` will delete the comment. However,
it will not delete a top-level comment like this one.
## Use Cases
Most will want to do one or both of these options:
1. Override/Patch a package's dependency
2. Add a package not already in the default package set
This file will continue to work whether you use one or both options.
Instructions for each option are explained below.
### Overriding/Patching a package
Purpose:
- Change a package's dependency to a newer/older release than the
default package set's release
- Use your own modified version of some dependency that may
include new API, changed API, removed API by
using your custom git repo of the library rather than
the package set's repo
Syntax:
Replace the overrides' "{=}" (an empty record) with the following idea
The "//" or "⫽" means "merge these two records and
when they have the same value, use the one on the right:"
-------------------------------
let overrides =
{ packageName =
upstream.packageName // { updateEntity1 = "new value", updateEntity2 = "new value" }
, packageName =
upstream.packageName // { version = "v4.0.0" }
, packageName =
upstream.packageName // { repo = "https://www.example.com/path/to/new/repo.git" }
}
-------------------------------
Example:
-------------------------------
let overrides =
{ halogen =
upstream.halogen // { version = "master" }
, halogen-vdom =
upstream.halogen-vdom // { version = "v4.0.0" }
}
-------------------------------
### Additions
Purpose:
- Add packages that aren't already included in the default package set
Syntax:
Replace the additions' "{=}" (an empty record) with the following idea:
-------------------------------
let additions =
{ package-name =
{ dependencies =
[ "dependency1"
, "dependency2"
]
, repo =
"https://example.com/path/to/git/repo.git"
, version =
"tag ('v4.0.0') or branch ('master')"
}
, package-name =
{ dependencies =
[ "dependency1"
, "dependency2"
]
, repo =
"https://example.com/path/to/git/repo.git"
, version =
"tag ('v4.0.0') or branch ('master')"
}
, etc.
}
-------------------------------
Example:
-------------------------------
let additions =
{ benchotron =
{ dependencies =
[ "arrays"
, "exists"
, "profunctor"
, "strings"
, "quickcheck"
, "lcg"
, "transformers"
, "foldable-traversable"
, "exceptions"
, "node-fs"
, "node-buffer"
, "node-readline"
, "datetime"
, "now"
]
, repo =
"https://github.com/hdgarrood/purescript-benchotron.git"
, version =
"v7.0.0"
}
}
-------------------------------
-}
let upstream =
https://github.com/purescript/package-sets/releases/download/psc-0.13.8-20201125/packages.dhall sha256:ef58d9afae22d1bc9d83db8c72d0a4eca30ce052ab49bbc44ced2da0bc5cad1a
let overrides = {=}
let additions = {=}
in upstream // overrides // additions

16
typelevel/spago.dhall Normal file
View file

@ -0,0 +1,16 @@
{-
Welcome to a Spago project!
You can edit this file as you like.
-}
{ name = "my-project"
, dependencies =
[ "console"
, "effect"
, "psci-support"
, "tuples"
, "typelevel-prelude"
, "undefined"
]
, packages = ./packages.dhall
, sources = [ "src/**/*.purs", "test/**/*.purs" ]
}

256
typelevel/src/Ast.purs Normal file
View file

@ -0,0 +1,256 @@
-- | Lambda calculus ast
module Ast where
import Data.Symbol (SProxy(..))
import Num (class NAreEqual, NProxy(..), Succ, Zero, kind Num)
import Num as Nat
import Ordering (class OrdsAreEqual)
import Prim.Boolean (False, True, kind Boolean)
import Prim.Ordering (GT, LT, kind Ordering)
import Prim.Symbol (class Append, class Compare, class Cons)
import Type.Data.Boolean (class And, class If, class Not)
foreign import kind Ast
foreign import data Var :: Symbol -> Ast
foreign import data Call :: Ast -> Ast -> Ast
foreign import data Lambda :: Symbol -> Ast -> Ast
foreign import kind Left
foreign import kind Right
foreign import kind Either
foreign import data Left :: Symbol -> Either
foreign import data Right :: Right -> Either
foreign import data RightUnit_ :: Right
foreign import data RightSymbol_ :: Symbol -> Right
foreign import data RightAst :: Ast -> Right
type RightSymbol a = Right (RightSymbol_ a)
type RightUnit = Right RightUnit_
foreign import kind ParsingResult
foreign import data ParsingResult :: Either -> Symbol -> ParsingResult
data PRProxy (a :: ParsingResult) = PRProxy
data EProxy (a :: Either) = EProxy
-------------- Typeclasses
-- Conditionals
class EIf (bool :: Boolean)
(onTrue :: Either)
(onFalse :: Either)
(output :: Either)
| bool onTrue onFalse -> output
instance eifTrue :: EIf True onTrue onFalse onTrue
instance eifFalse :: EIf False onTrue onFalse onFalse
-- Merge 2 eithers
class MergeEithers (a :: Either) (b :: Either) (c :: Either) | a b -> c
instance mergeEithersLeft :: MergeEithers (Left err) right (Left err)
else instance mergeEithersLeft' :: MergeEithers left (Left err) (Left err)
else instance mergeEithersRight :: MergeEithers left right right
-- Check if 2 symbols are equal
class SymbolsAreEqual (a :: Symbol) (b :: Symbol) (result :: Boolean) | a b -> result
instance saeT :: SymbolsAreEqual a a True
else instance saeF :: SymbolsAreEqual a b False
-- Measure length of string
class Length (input :: Symbol) (output :: Num) | input -> output
instance lengthEmpty :: Length "" Zero
else instance lengthCons ::
( Cons head tail input
, Length tail length
) => Length input (Succ length)
-- Actual parsing
class ParseAst (input :: Symbol) (result :: Ast) | input -> result
-- Parses a literal thing.
class ParseLiteral (lit :: Symbol) (input :: Symbol) (result :: ParsingResult) | lit input -> result
instance parseLiteralGeneral' ::
( Length literal litLength
, Length input inputLength
, Nat.Compare inputLength litLength ord
, ParseLiteralEnsureCorrectLength ord literal input result
) => ParseLiteral literal input result
class ParseLiteralEnsureCorrectLength (ord :: Ordering) (lit :: Symbol) (input :: Symbol) (result :: ParsingResult) | ord lit input -> result
instance parseLiteralEnsureCorrectLengthLT ::
Append "Not enough input text to match literal " literal error
=> ParseLiteralEnsureCorrectLength LT literal input (ParsingResult (Left error) input)
else instance parseLitealEnsureCorrectLengthGeneral ::
ParseLiteral' literal input result
=> ParseLiteralEnsureCorrectLength ord literal input result
class ParseLiteral' (lit :: Symbol) (input :: Symbol) (result :: ParsingResult) | lit input -> result
instance parseLiteralEmpty :: ParseLiteral' "" input (ParsingResult (Right RightUnit_) input)
else instance parseLiteralGeneral ::
( Cons litHead litTail literal
, Cons litInput inputTail input
, SymbolsAreEqual litHead litInput areEqual
, Append "Expected " litHead error
, EIf areEqual RightUnit (Left error) result
, ParseLiteral' litTail inputTail (ParsingResult result' remaining)
, MergeEithers result result' result''
) => ParseLiteral' literal input (ParsingResult result'' remaining)
-- Skips whitespace
class SkipWhitespace (input :: Symbol) (result :: Symbol) | input -> result
instance skipWhitespaceEmpty :: SkipWhitespace "" ""
else instance skipWhitespaceNonEmpty ::
( Cons head tail input
, SymbolsAreEqual head " " equal
, SkipWhitespace tail tailResult
, If equal (SProxy tailResult) (SProxy input) (SProxy result)
) => SkipWhitespace input result
-- Lambda parsing
class ParseLambda (input :: Symbol) (result :: ParsingResult) | input -> result
instance parseLambdaGeneral ::
( ParseLiteral "\\" input (ParsingResult either remaining)
, SkipWhitespace remaining remaining'
, ParseIdentifier remaining' (ParsingResult arg remaining'')
, SkipWhitespace remaining'' remaining'''
, ParseLiteral "." remaining''' (ParsingResult either' remaining'''')
, SkipWhitespace remaining'''' remaining'''''
, ParseIdentifier remaining''''' (ParsingResult body remaining'''''')
, MergeEithers either either' mergedEither
, MergeEithers arg body mergedEither'
, MergeEithers mergedEither mergedEither' mergedEither''
, ParseLambda' mergedEither'' arg body remaining'''''' result
) => ParseLambda input result
class ParseLambda'
(either :: Either)
(arg :: Either)
(body :: Either)
(input :: Symbol)
(result :: ParsingResult)
| either input -> result
instance parseLambda'Left :: ParseLambda' (Left left) arg body remaining (ParsingResult (Left left) remaining)
else instance parseLambda'Right ::
ParseLambda'
right
(Right (RightSymbol_ arg))
(Right (RightSymbol_ body))
remaining
(ParsingResult (Right (RightAst (Lambda arg (Var body)))) remaining)
-- Parses a single alphabetic character
class IsAlphaChar (input :: Symbol) (result :: Boolean) | input -> result
instance isAlphaChar ::
( Compare "@" input a
, Compare "{" input b
, OrdsAreEqual a LT a'
, OrdsAreEqual b GT b'
, And a' b' result
) => IsAlphaChar input result
-- Parses a single identifier
class ParseIdentifier (input :: Symbol) (result :: ParsingResult) | input -> result
instance parseIdentifierEnsureCorrectLength ::
( ParseIdentifier' input result remaining
, Length result resultLength
, NAreEqual resultLength Zero empty
, Not empty success
, EIf empty (Left "Empty identifier") (RightSymbol result) result'
) => ParseIdentifier input (ParsingResult result' remaining)
class ParseIdentifier' (input :: Symbol) (result :: Symbol) (remaining :: Symbol) | input -> result remaining
instance parseIdentifierGeneral ::
( IsAlphaChar input good
, ParseIdentifier'' good input result remaining
) => ParseIdentifier' input result remaining
class ParseIdentifier''
(goodFirstChar :: Boolean)
(input :: Symbol)
(result :: Symbol)
(remaining :: Symbol) | goodFirstChar input -> result remaining
instance parseIdentifierGood ::
( Cons head remaining input
, ParseIdentifier' remaining tail remaining'
, Append head tail result
) => ParseIdentifier'' True input result remaining'
else instance parseIdentifierBad :: ParseIdentifier'' False input "" input
-- Helpers
length :: forall s n. Length s n => SProxy s -> NProxy n
length _ = NProxy
parseIdentifier ::
forall input result.
ParseIdentifier input result =>
SProxy input ->
PRProxy result
parseIdentifier _ = PRProxy
parseLambda ::
forall input result.
ParseLambda input result =>
SProxy input ->
PRProxy result
parseLambda _ = PRProxy
parseLiteral ::
forall literal input result.
ParseLiteral literal input result =>
SProxy literal ->
SProxy input ->
PRProxy result
parseLiteral _ _ = PRProxy
-- Tests
-- Parse identifier
a :: PRProxy (ParsingResult (Left "Empty identifier") "")
a = parseIdentifier (SProxy :: SProxy "")
b :: PRProxy (ParsingResult (Right (RightSymbol_ "abc")) "")
b = parseIdentifier (SProxy :: SProxy "abc")
c :: PRProxy (ParsingResult (Right (RightSymbol_ "abc")) " something else CAPS")
c = parseIdentifier (SProxy :: SProxy "abc something else CAPS")
d :: PRProxy (ParsingResult (Left "Empty identifier") " doesn\'t automatically skip whitespace")
d = parseIdentifier (SProxy :: SProxy " doesn't automatically skip whitespace")
-- Parsing literals
lit :: PRProxy (ParsingResult (Right RightUnit_) " hmmmm!!!")
lit = parseLiteral (SProxy :: SProxy "something") (SProxy :: SProxy "something hmmmm!!!")
lit' :: PRProxy (ParsingResult (Left "Expected s") "ing hmmmm!!!")
lit' = parseLiteral (SProxy :: SProxy "something") (SProxy :: SProxy " something hmmmm!!!")
lit'' :: PRProxy (ParsingResult (Left "Not enough input text to match literal something") "someth")
lit'' = parseLiteral (SProxy :: SProxy "something") (SProxy :: SProxy "someth")
lit''' :: PRProxy (ParsingResult (Left "Expected e") "g hmmm")
lit''' = parseLiteral (SProxy :: SProxy "something") (SProxy :: SProxy "somnething hmmm")
lit'''' :: PRProxy (ParsingResult (Left "Expected s") "mmm")
lit'''' = parseLiteral (SProxy :: SProxy "something") (SProxy :: SProxy "zomethi hmmm")
-- Lambda parsing
lam :: PRProxy (ParsingResult (Right (RightAst (Lambda "a" (Var "a")))) "")
lam = parseLambda (SProxy :: SProxy "\\a. a")
-- Lenghts
lengthTest :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
lengthTest = length (SProxy :: SProxy "Adriel")

69
typelevel/src/Fin.purs Normal file
View file

@ -0,0 +1,69 @@
module Data.Fin where
import Prelude
import Data.Leibniz (type (~), coerce, liftLeibniz, liftLeibniz1of2, lowerLeibniz, refute, symm)
import Type.Proxy (Proxy)
import Unsafe.Coerce (unsafeCoerce)
data Nat
foreign import data Z :: Nat
foreign import data S :: Nat -> Nat
foreign import data Add :: Nat -> Nat -> Nat
addZ :: forall a. Add Z a ~ a
addZ = unsafeCoerce \u -> u
addS :: forall a b. Add (S a) b ~ S (Add a b)
addS = unsafeCoerce \u -> u
data Vec s a
= Nil (s ~ Z)
| Cons a (forall r. (forall p. S p ~ s -> Vec p a -> r) -> r)
nil :: forall a. Vec Z a
nil = Nil identity
cons :: forall a n. a -> Vec n a -> Vec (S n) a
cons head tail = Cons head \f -> f identity tail
data Fin n
= FZ (forall r. (forall p. S p ~ n -> r) -> r)
| FS (forall r. (forall p. S p ~ n -> Fin p -> r) -> r)
fz :: forall n. Fin (S n)
fz = FZ \f -> f identity
fs :: forall n. Fin n -> Fin (S n)
fs p = FS \f -> f identity p
refuteFinZero :: Fin Z -> Void
refuteFinZero (FZ oops) = oops \eq -> refute (liftLeibniz eq :: Proxy _ ~ Proxy _)
refuteFinZero (FS oops) = oops \eq _ -> refute (liftLeibniz eq :: Proxy _ ~ Proxy _)
succInj :: forall a b. S a ~ S b -> a ~ b
succInj = lowerLeibniz
lookup :: forall l a. Vec l a -> Fin l -> a
lookup (Cons a _) (FZ _) = a
lookup (Cons _ nextVec) (FS nextFin) =
nextFin \eq finP ->
nextVec \eq' vecP -> do
let trans = liftLeibniz (succInj (eq >>> symm eq'))
lookup vecP (coerce trans finP)
lookup (Nil lenIsZero) fin = absurd $ refuteFinZero (coerce finIsFinZero fin)
where
finIsFinZero :: Fin l ~ Fin Z
finIsFinZero = liftLeibniz lenIsZero
concat :: forall n m a. Vec n a -> Vec m a -> Vec (Add n m) a
concat (Nil nIsZ) other = coerce
(liftLeibniz1of2 (symm addZ >>> liftLeibniz1of2 (symm nIsZ)))
other
concat (Cons e nextVec) other = nextVec \eq vecP -> do
coerce
(liftLeibniz1of2 (symm addS >>> liftLeibniz1of2 eq))
(cons e (concat vecP other))

10
typelevel/src/Main.purs Normal file
View file

@ -0,0 +1,10 @@
module Main where
import Prelude
import Effect (Effect)
import Effect.Console (log)
main :: Effect Unit
main = do
log "🍝"

251
typelevel/src/Num.purs Normal file
View file

@ -0,0 +1,251 @@
module Num where
import Data.Symbol (SProxy(..))
import Data.Unit (Unit, unit)
import Prim.Boolean (False, True, kind Boolean)
import Prim.Ordering (EQ, GT, LT, kind Ordering)
import Prim.Symbol (class Cons)
foreign import kind Num
foreign import data Zero :: Num
foreign import data Succ :: Num -> Num
data NProxy (i :: Num)
= NProxy
-- Predecessor
class Pred (input :: Num) (output :: Num) | input -> output, output -> input
instance predSucc :: Pred (Succ a) a
-- Conditionals
class NumIf
(bool :: Boolean)
(onTrue :: Num)
(onFalse :: Num)
(output :: Num)
| bool onTrue onFalse -> output
instance ifTrue :: NumIf True onTrue onFalse onTrue
instance ifFalse :: NumIf False onTrue onFalse onFalse
-- Addition
class Add (a :: Num) (b :: Num) (output :: Num)
| a b -> output
, a output -> b
instance addZero :: Add Zero a a
else instance addSucc :: Add a b c => Add (Succ a) b (Succ c)
-- Substraction
class Sub (a :: Num) (b :: Num) (output :: Num)
| a b -> output
, b output -> a
instance subZero :: Sub a Zero a
else instance subSucc :: Sub a b c => Sub (Succ a) (Succ b) c
-- Multiplication
class Multiply (a :: Num) (b :: Num) (output :: Num)
| a b -> output
instance multiplyZero :: Multiply Zero a Zero
else instance multiplySucc :: (Multiply a b c, Add b c result) => Multiply (Succ a) b result
-- Division
class Divide'
(a :: Num)
(b :: Num)
(result :: Num)
(mod :: Num)
(ord :: Ordering)
| a b ord -> result mod
instance divideZero :: Divide' Zero a Zero Zero LT
else instance divideMod :: Divide' a b Zero a LT
else instance divideSucc :: (Divide a b result mod, Sub a' b a) => Divide' a' b (Succ result) mod ord
class Divide
(a :: Num)
(b :: Num)
(result :: Num)
(mod :: Num)
| a b -> result mod
instance divideAndCompare :: (Compare a b ord, Divide' a b result mod ord) => Divide a b result mod
-- Raising to power
class Pow (base :: Num) (power :: Num) (output :: Num)
| base power -> output
-- Does this work?
-- , power output -> base
instance powZero :: Pow Zero a (Succ Zero)
else instance powOne :: Pow a (Succ Zero) a
else instance powSucc :: (Pow a b c, Multiply c a result) => Pow a (Succ b) result
-- Equality checking
class NAreEqual (a :: Num) (b :: Num) (result :: Boolean) | a b -> result
instance areEqualZero :: NAreEqual Zero Zero True
else instance areEqualSucc :: NAreEqual a b c => NAreEqual (Succ a) (Succ b) c
else instance areNotEqual :: NAreEqual a b False
class Factorial (input :: Num) (output :: Num) | input -> output
instance factorialZero :: Factorial Zero (Succ Zero)
instance factorialSucc :: (Factorial a a', Multiply a' (Succ a) result) => Factorial (Succ a) result
-- Ordering
class Compare (a :: Num) (b :: Num) (output :: Ordering)
| a b -> output
instance compareEqual :: Compare Zero Zero EQ
else instance compareZeroLower :: Compare Zero a LT
else instance compareZeroGreater :: Compare a Zero GT
else instance compareSucc :: Compare a b c => Compare (Succ a) (Succ b) c
-- Parsing
class ParseNum (input :: Symbol) (output :: Num) | input -> output
instance parseNum :: (Cons head tail input, ParseNum' head tail output) => ParseNum input output
class ParseNum' (head :: Symbol) (tail :: Symbol) (output :: Num) | head tail -> output
instance parseNumSingle :: ParseDigit input result => ParseNum' input "" result
else instance parseNumHeadTail ::
( ParseDigit head resultHead
, ParseNum tail resultTail
, Multiply resultHead (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))) result'
, Add result' resultTail result )
=> ParseNum' head tail result
class ParseDigit (input :: Symbol) (output :: Num) | input -> output, output -> input
instance parseDigit0 :: ParseDigit "0" Zero
instance parseDigit1 :: ParseDigit "1" (Succ Zero)
instance parseDigit2 :: ParseDigit "2" (Succ (Succ Zero))
instance parseDigit3 :: ParseDigit "3" (Succ (Succ (Succ Zero)))
instance parseDigit4 :: ParseDigit "4" (Succ (Succ (Succ (Succ Zero))))
instance parseDigit5 :: ParseDigit "5" (Succ (Succ (Succ (Succ (Succ Zero)))))
instance parseDigit6 :: ParseDigit "6" (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
instance parseDigit7 :: ParseDigit "7" (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))
instance parseDigit8 :: ParseDigit "8" (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))
instance parseDigit9 :: ParseDigit "9" (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))
-- Constructors
zero :: NProxy Zero
zero = NProxy
succ :: forall a. NProxy a -> NProxy (Succ a)
succ _ = NProxy
pred :: forall i o. Pred i o => NProxy i -> NProxy o
pred _ = NProxy
add :: forall a b c. Add a b c => NProxy a -> NProxy b -> NProxy c
add _ _ = NProxy
sub :: forall a b c. Sub a b c => NProxy a -> NProxy b -> NProxy c
sub _ _ = NProxy
multiply :: forall a b c. Multiply a b c => NProxy a -> NProxy b -> NProxy c
multiply _ _ = NProxy
pow :: forall a b c. Pow a b c => NProxy a -> NProxy b -> NProxy c
pow _ _ = NProxy
divide ::forall a b c d. Divide a b c d => NProxy a -> NProxy b -> { result :: NProxy c, mod :: NProxy d }
divide _ _ = { mod: NProxy, result: NProxy }
div :: forall a b c d. Divide a b c d => NProxy a -> NProxy b -> NProxy c
div _ _ = NProxy
mod :: forall a b c d. Divide a b c d => NProxy a -> NProxy b -> NProxy d
mod _ _ = NProxy
parse :: forall a n. ParseNum a n => SProxy a -> NProxy n
parse _ = NProxy
equal :: forall a b. NAreEqual a b True => NProxy a -> NProxy b -> Unit
equal _ _ = unit
factorial :: forall a b. Factorial a b => NProxy a -> NProxy b
factorial _ = NProxy
-- Basic values
type One = Succ Zero
type Two = Succ One
type Three = Succ Two
type Four = Succ Three
type Five = Succ Four
type Six = Succ Five
type Seven = Succ Six
type Eight = Succ Seven
type Nine = Succ Eight
type Ten = Succ Nine
-- Tests
one :: NProxy One
one = succ zero
two :: NProxy Two
two = succ one
three :: NProxy Three
three = succ two
five :: NProxy (Succ (Succ (Succ (Succ (Succ Zero)))))
five = add two three
-- Solvable when the first param is missing
two' :: NProxy Two
two' = sub five three
six :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
six = multiply three two
fifteen :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
fifteen = multiply three two
eight :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))
eight = pow two three
one' :: NProxy (Succ Zero)
one' = pow zero three
four :: NProxy (Succ Three)
four = succ three
five' :: NProxy (Succ (Succ (Succ (Succ Zero))))
five' = pow two two
where
_25 = add two (add eight fifteen)
sixDivThree :: NProxy (Succ (Succ Zero))
sixDivThree = div six three
sevenDivThree ::
{ mod :: NProxy (Succ Zero)
, result :: NProxy (Succ (Succ Zero))
}
sevenDivThree = divide (succ six) three
parse13 :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero)))))))))))))
parse13 = parse _13
where
_13 :: SProxy "13"
_13 = SProxy
parse64 :: Unit
parse64 = equal (parse _64) (pow two six)
where
_64 :: SProxy "64"
_64 = SProxy
fac3 :: NProxy (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))
fac3 = factorial (parse _3)
where
_3 :: SProxy "3"
_3 = SProxy

View file

@ -0,0 +1,10 @@
module Ordering where
import Prim.Boolean (False, True, kind Boolean)
import Prim.Ordering (kind Ordering)
-- Compare 2 orderings
class OrdsAreEqual (a :: Ordering) (b :: Ordering) (result :: Boolean) | a b -> result
instance oaeGT :: OrdsAreEqual a a True
else instance oaeGeneral :: OrdsAreEqual a b False

299
typelevel/src/Term.purs Normal file
View file

@ -0,0 +1,299 @@
module Term where
import Num (class Add, class Compare, class NAreEqual, class Sub, NProxy, Succ, Zero, five, four, one, three, two, zero, kind Num)
import Prim.Boolean (False, True, kind Boolean)
import Prim.Ordering (GT, kind Ordering)
import Type.Data.Boolean (class And, class Or, BProxy(..))
foreign import kind Term
foreign import data Var :: Num -> Term
foreign import data Abstraction :: Term -> Term
foreign import data Application :: Term -> Term -> Term
-- Reduce
class Reduce (input :: Term) (output :: Term) | input -> output
instance reduceGeneral ::
( BetaReduce a b
, EtaReduce b c
) => Reduce a c
-- Checking if an expression references a variable
class HasReference (term :: Term) (index :: Num) (output :: Boolean) | term index -> output
instance hasReferenceVar ::
NAreEqual index var result
=> HasReference (Var var) index result
else instance hasReferenceCall ::
(HasReference left index leftResult
, HasReference right index rightResult
, Or leftResult rightResult result
) => HasReference (Application left right) index result
else instance hasReferenceAbstraction ::
HasReference term (Succ index) result
=> HasReference (Abstraction term) index result
-- Shifting
class ShiftTerm
(term :: Term)
(over :: Num)
(direction :: Boolean)
(amount :: Num)
(result :: Term)
| term over direction amount -> result
instance shiftTermApplication ::
( ShiftTerm left over sign amount leftResult
, ShiftTerm right over sign amount rightResult )
=> ShiftTerm (Application left right) over sign amount (Application leftResult rightResult)
else instance shiftTermAbstraction ::
ShiftTerm term (Succ over) sign amount result
=> ShiftTerm (Abstraction term) over sign amount (Abstraction result)
else instance shiftTermVar ::
( Compare (Succ index) over ord
, ShiftVar ord index sign amount result )
=> ShiftTerm (Var index) over sign amount (Var result)
class ShiftVar
(ord :: Ordering)
(index :: Num)
(sign :: Boolean)
(amount :: Num)
(result :: Num)
| index sign amount ord -> result
instance shiftVarGTPositive ::
Add index amount result
=> ShiftVar GT index True amount result
else instance shiftVarGTNegative ::
Sub index amount result
=> ShiftVar GT index False amount result
else instance shiftVarGeneral :: ShiftVar ord index sign amount index
-- Equality
class TermsAreEqual (a :: Term) (b :: Term) (result :: Boolean) | a b -> result
instance termsAreEqualVar :: NAreEqual a b result => TermsAreEqual (Var a) (Var b) result
else instance termsAreEqualAbstraction :: TermsAreEqual a b result => TermsAreEqual (Abstraction a) (Abstraction b) result
else instance termsAreEqualApplication ::
( TermsAreEqual left left' leftResult
, TermsAreEqual right right' rightResult
, And leftResult rightResult result )
=> TermsAreEqual (Application left right) (Application left' right') result
else instance termsAreEqualGeneral :: TermsAreEqual a b False
-- Eta reduction
class EtaReduceAbstraction (input :: Term) (hasReference :: Boolean) (output :: Term) | input hasReference -> output
instance etaReduceLambdaFalse ::
( ShiftTerm term Zero False (Succ Zero) result
, DeepEtaReduce result deepResult )
=> EtaReduceAbstraction term False deepResult
else instance etaReduceLambdaTrue ::
DeepEtaReduce term result
=> EtaReduceAbstraction term True (Abstraction (Application result (Var Zero)))
class DeepEtaReduce (input :: Term) (output :: Term) | input -> output
instance deepEtaReduceAbstraction ::
( HasReference term Zero hasReference
, EtaReduceAbstraction term hasReference result)
=> DeepEtaReduce (Abstraction (Application term (Var Zero))) result
else instance deepEtaReduceApplication ::
( DeepEtaReduce left leftResult
, DeepEtaReduce right rightResult)
=> DeepEtaReduce (Application left right) (Application leftResult rightResult)
else instance deepEtaReduceAbstraction' ::
DeepEtaReduce term result
=> DeepEtaReduce (Abstraction term) (Abstraction result)
else instance deepEtaReduceGeneral :: DeepEtaReduce a a
class EtaReduce (input :: Term) (output :: Term) | input -> output
instance etaReduceGeneral ::
( DeepEtaReduce input reduced
, TermsAreEqual input reduced equal
, EtaReduceRec reduced equal result )
=> EtaReduce input result
class EtaReduceRec (reduced :: Term) (equal :: Boolean) (output :: Term) | reduced equal -> output
instance etaReduceTrue :: EtaReduceRec reduced True reduced
else instance etaReduceFalse :: EtaReduce reduced result => EtaReduceRec reduced False result
-- Conditions
class TermIf (bool :: Boolean)
(onTrue :: Term)
(onFalse :: Term)
(output :: Term)
| bool onTrue onFalse -> output
instance ifTrue :: TermIf True onTrue onFalse onTrue
instance ifFalse :: TermIf False onTrue onFalse onFalse
-- Substitution
class Substitute (index :: Num) (inside :: Term) (with :: Term) (result :: Term) | index inside with -> result
instance substituteVar ::
( NAreEqual var index equal
, TermIf equal with (Var var) result)
=> Substitute index (Var var) with result
else instance substituteCall ::
( Substitute index left with leftResult
, Substitute index right with rightResult
) => Substitute index (Application left right) with (Application leftResult rightResult)
else instance subsituteAbstraction ::
( ShiftTerm with Zero True (Succ Zero) shifted
, Substitute (Succ index) term shifted result
) => Substitute index (Abstraction term) with (Abstraction result)
-- Beta reduction
class DeepBetaReduce (term :: Term) (result :: Term) | term -> result
instance deepBetaReduceAbstraction :: DeepBetaReduce term result => DeepBetaReduce (Abstraction term) (Abstraction result)
else instance deepBetaReudctionApplication ::
( DeepBetaReduce left leftReduced
, DeepBetaReduce right rightReduced
, ShiftTerm rightReduced Zero True (Succ Zero) rightShifted
, Substitute Zero leftReduced rightShifted result
, ShiftTerm result Zero False (Succ Zero) result'
-- , DeepBetaReduce result' result''
) => DeepBetaReduce (Application (Abstraction left) right) result'
else instance deepBetaReduceApplication ::
( DeepBetaReduce left leftResult
, DeepBetaReduce right rightResult
) => DeepBetaReduce (Application left right) (Application leftResult rightResult)
else instance deepBetaReduceGeneral :: DeepBetaReduce a a
class BetaReduce (input :: Term) (output :: Term) | input -> output
instance betaReduceGeneral ::
( DeepBetaReduce input reduced
, TermsAreEqual input reduced equal
, BetaReduceRec reduced equal result
) => BetaReduce input result
class BetaReduceRec (reduced :: Term) (equal :: Boolean) (output :: Term) | reduced equal -> output
instance betaReduceTrue :: BetaReduceRec reduced True reduced
else instance betaReduceFalse :: BetaReduce reduced result => BetaReduceRec reduced False result
-- Church numerals
class ChurchNumeral (input :: Num) (output :: Term) | input -> output
instance churchNumeralGeneral ::
ChurchNumeralBody x result
=> ChurchNumeral x (Abstraction (Abstraction result))
class ChurchNumeralBody (input :: Num) (output :: Term) | input -> output
instance churchNumeralZero :: ChurchNumeralBody Zero (Var Zero)
else instance churchNumeralSucc ::
ChurchNumeralBody x result
=> ChurchNumeralBody (Succ x) (Application (Var (Succ Zero)) result)
-- Helpers
data TProxy (a :: Term) = TProxy
var :: forall a. NProxy a -> TProxy (Var a)
var _ = TProxy
abstract :: forall a. TProxy a -> TProxy (Abstraction a)
abstract _ = TProxy
application :: forall a b. TProxy a -> TProxy b -> TProxy (Application a b)
application _ _ = TProxy
infixl 1 application as -$-
hasReference :: forall term index result.
HasReference term index result =>
TProxy term ->
NProxy index ->
BProxy result
hasReference _ _ = BProxy
etaReduce :: forall input output. EtaReduce input output => TProxy input -> TProxy output
etaReduce _ = TProxy
betaReduce :: forall input output. BetaReduce input output => TProxy input -> TProxy output
betaReduce _ = TProxy
reduce :: forall input output. Reduce input output => TProxy input -> TProxy output
reduce _ = TProxy
shiftVar :: forall term over amount result sign.
ShiftTerm term over sign amount result =>
TProxy term ->
NProxy over ->
BProxy sign ->
NProxy amount ->
TProxy result
shiftVar _ _ _ _ = TProxy
churchNumeral :: forall int result. ChurchNumeral int result => NProxy int -> TProxy result
churchNumeral _ = TProxy
areEqual :: forall a b r. TermsAreEqual a b r => TProxy a -> TProxy b -> BProxy r
areEqual _ _ = BProxy
-- Tests
referenceTest :: BProxy True
referenceTest = hasReference term index
where
term = abstract (abstract (application (var one) (var two)))
index = zero
etaTest :: TProxy (Abstraction (Application (Var Zero) (Var (Succ Zero))))
etaTest = etaReduce expression
where
-- Equivalent of (\a b. (\b. b c) a b)
expression = abstract (abstract (application (application (abstract (application (var zero) (var three))) (var one)) (var zero)))
churchZero :: TProxy (Abstraction (Abstraction (Var Zero)))
churchZero = churchNumeral zero
churchOne :: TProxy (Abstraction (Abstraction (Application (Var (Succ Zero)) (Var Zero))))
churchOne = churchNumeral one
churchThree :: TProxy (Abstraction (Abstraction (Application (Var (Succ Zero)) (Application (Var (Succ Zero)) (Application (Var (Succ Zero)) (Var Zero))))))
churchThree = churchNumeral three
churchAdd :: TProxy (Abstraction (Abstraction (Abstraction (Abstraction (Application (Application (Var (Succ (Succ (Succ Zero)))) (Var (Succ Zero))) (Application (Application (Var (Succ (Succ Zero))) (Var (Succ Zero))) (Var Zero)))))))
churchAdd = abstract (abstract (abstract (abstract body)))
where
body :: TProxy _
body = (var three) -$- (var one) -$- ((var two) -$- (var one) -$- (var zero))
churchFiveUnReduced :: TProxy (Application (Application (Abstraction (Abstraction (Abstraction (Abstraction (Application (Application (Var (Succ (Succ (Succ Zero)))) (Var (Succ Zero))) (Application (Application (Var (Succ (Succ Zero))) (Var (Succ Zero))) (Var Zero))))))) (Abstraction (Abstraction (Application (Var (Succ Zero)) (Application (Var (Succ Zero)) (Application (Var (Succ Zero)) (Var Zero))))))) (Abstraction (Abstraction (Application (Var (Succ Zero)) (Var Zero)))))
churchFiveUnReduced = churchAdd -$- churchThree -$- churchOne
termConst :: TProxy (Abstraction (Abstraction (Var (Succ Zero))))
termConst = abstract (abstract (var one))
termIdentity :: TProxy (Abstraction (Var Zero))
termIdentity = abstract (var zero)
addTest :: BProxy True
addTest = areEqual fourRaw fourComputed
where
fourRaw = churchNumeral four
fourComputed = reduce (churchAdd -$- churchThree -$- churchOne)
addTest' :: BProxy False
addTest' = areEqual fiveRaw fourComputed
where
fiveRaw = churchNumeral five
fourComputed = reduce (churchAdd -$- churchThree -$- churchOne)
reductionTest :: TProxy (Abstraction (Abstraction (Var Zero)))
reductionTest = reduce (f -$- arg -$- arg)
where
f = termConst -$- termIdentity
arg = churchZero
-- infinite :: _
-- infinite = reduce (abstract (t -$- t))
-- where
-- t = abstract (var one -$- (var zero -$- var zero))

53
typelevel/src/Vec.purs Normal file
View file

@ -0,0 +1,53 @@
module Vec where
import Num
import Data.Tuple (Tuple)
import Prim.Ordering (LT)
import Undefined (undefined)
foreign import data Vec :: Num -> Type -> Type
-- Helpers
cons :: forall length a. a -> Vec length a -> Vec (Succ length) a
cons = undefined
nil :: forall a. Vec Zero a
nil = undefined
merge :: forall l1 l2 l3 a. Add l1 l2 l3 => Vec l1 a -> Vec l2 a -> Vec l3 a
merge = undefined
lookup :: forall length index a. Compare index length LT => Vec length a -> NProxy index -> a
lookup = undefined
take :: forall l i a. Compare i l LT => NProxy i -> Vec l a -> Vec i a
take = undefined
drop :: forall l l' i a. Sub l i l' => NProxy i -> Vec l a -> Vec l' a
drop = undefined
product :: forall l l' l'' a b. Multiply l l' l'' => Vec l a -> Vec l' b -> Vec l'' (Tuple a b)
product = undefined
-- Test
myVec :: Vec Three String
myVec = undefined
first :: String
first = lookup myVec zero
second :: String
second = lookup myVec one
third :: String
third = lookup myVec two
getFourth :: forall a l. Compare Three l LT => Vec l a -> a
getFourth a = lookup a three
lastTwo :: Vec Two String
lastTwo = drop two (cons "something" myVec)
productTest :: Vec (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ (Succ Zero))))))))) (Tuple String Int)
productTest = product (myVec) (cons 1 (cons 4 (cons 7 nil)))

11
typelevel/test/Main.purs Normal file
View file

@ -0,0 +1,11 @@
module Test.Main where
import Prelude
import Effect (Effect)
import Effect.Class.Console (log)
main :: Effect Unit
main = do
log "🍝"
log "You should add some tests."