1
1
mirror of https://github.com/anoma/juvix.git synced 2024-12-11 08:25:46 +03:00

Add holes for expressions in function clauses and inference support (#136)

* Add holes to abstract and micro

* Support trivial implicit arguments

* Support refinement of meta type variables
This commit is contained in:
janmasrovira 2022-06-01 17:54:53 +02:00 committed by GitHub
parent 29c526833d
commit bd110723df
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
28 changed files with 922 additions and 82 deletions

View File

@ -1,6 +1,6 @@
* Monomorphization #+author: Jan Mas Rovira
/By Jan Mais Rovira/ * Monomorphization
Monomorphization refers to the process of converting polymorphic code to Monomorphization refers to the process of converting polymorphic code to
monomorphic code (no type variables) through static analysis. monomorphic code (no type variables) through static analysis.

View File

@ -1,6 +1,7 @@
module MiniJuvix.Syntax.Abstract.Language module MiniJuvix.Syntax.Abstract.Language
( module MiniJuvix.Syntax.Abstract.Language, ( module MiniJuvix.Syntax.Abstract.Language,
module MiniJuvix.Syntax.Concrete.Language, module MiniJuvix.Syntax.Concrete.Language,
module MiniJuvix.Syntax.Hole,
) )
where where
@ -9,6 +10,7 @@ import MiniJuvix.Syntax.Concrete.Language (BackendItem, ForeignBlock (..), Liter
import MiniJuvix.Syntax.Concrete.Name qualified as C import MiniJuvix.Syntax.Concrete.Name qualified as C
import MiniJuvix.Syntax.Concrete.Scoped.Name qualified as S import MiniJuvix.Syntax.Concrete.Scoped.Name qualified as S
import MiniJuvix.Syntax.Fixity import MiniJuvix.Syntax.Fixity
import MiniJuvix.Syntax.Hole
import MiniJuvix.Syntax.Universe import MiniJuvix.Syntax.Universe
type TopModuleName = S.TopModulePath type TopModuleName = S.TopModulePath
@ -102,6 +104,7 @@ data Expression
| ExpressionUniverse Universe | ExpressionUniverse Universe
| ExpressionFunction Function | ExpressionFunction Function
| ExpressionLiteral LiteralLoc | ExpressionLiteral LiteralLoc
| ExpressionHole Hole
--- | ExpressionMatch Match --- | ExpressionMatch Match
--- ExpressionLambda Lambda not supported yet --- ExpressionLambda Lambda not supported yet
deriving stock (Eq, Show) deriving stock (Eq, Show)
@ -109,6 +112,7 @@ data Expression
instance HasAtomicity Expression where instance HasAtomicity Expression where
atomicity e = case e of atomicity e = case e of
ExpressionIden {} -> Atom ExpressionIden {} -> Atom
ExpressionHole {} -> Atom
ExpressionUniverse u -> atomicity u ExpressionUniverse u -> atomicity u
ExpressionApplication a -> atomicity a ExpressionApplication a -> atomicity a
ExpressionFunction f -> atomicity f ExpressionFunction f -> atomicity f

View File

@ -26,12 +26,9 @@ smallerPatternVariables = \case
viewApp :: Expression -> (Expression, [Expression]) viewApp :: Expression -> (Expression, [Expression])
viewApp e = case e of viewApp e = case e of
ExpressionIden {} -> (e, [])
ExpressionApplication (Application l r) -> ExpressionApplication (Application l r) ->
second (`snoc` r) (viewApp l) second (`snoc` r) (viewApp l)
ExpressionUniverse {} -> (e, []) _ -> (e, [])
ExpressionFunction {} -> (e, [])
ExpressionLiteral {} -> (e, [])
viewExpressionAsPattern :: Expression -> Maybe Pattern viewExpressionAsPattern :: Expression -> Maybe Pattern
viewExpressionAsPattern e = case viewApp e of viewExpressionAsPattern e = case viewApp e of

View File

@ -131,6 +131,7 @@ instance PrettyCode Expression where
ExpressionApplication a -> ppCode a ExpressionApplication a -> ppCode a
ExpressionFunction f -> ppCode f ExpressionFunction f -> ppCode f
ExpressionLiteral l -> ppSCode l ExpressionLiteral l -> ppSCode l
ExpressionHole h -> ppSCode h
instance PrettyCode Usage where instance PrettyCode Usage where
ppCode u = return $ case u of ppCode u = return $ case u of

View File

@ -5,6 +5,7 @@ module MiniJuvix.Syntax.Concrete.Language
module MiniJuvix.Syntax.Concrete.Name, module MiniJuvix.Syntax.Concrete.Name,
module MiniJuvix.Syntax.Concrete.Scoped.NameRef, module MiniJuvix.Syntax.Concrete.Scoped.NameRef,
module MiniJuvix.Syntax.Concrete.Loc, module MiniJuvix.Syntax.Concrete.Loc,
module MiniJuvix.Syntax.Hole,
module MiniJuvix.Syntax.Concrete.LiteralLoc, module MiniJuvix.Syntax.Concrete.LiteralLoc,
module MiniJuvix.Syntax.Backends, module MiniJuvix.Syntax.Backends,
module MiniJuvix.Syntax.ForeignBlock, module MiniJuvix.Syntax.ForeignBlock,
@ -34,6 +35,7 @@ import MiniJuvix.Syntax.Concrete.Scoped.NameRef
import MiniJuvix.Syntax.Concrete.Scoped.VisibilityAnn import MiniJuvix.Syntax.Concrete.Scoped.VisibilityAnn
import MiniJuvix.Syntax.Fixity import MiniJuvix.Syntax.Fixity
import MiniJuvix.Syntax.ForeignBlock import MiniJuvix.Syntax.ForeignBlock
import MiniJuvix.Syntax.Hole
import MiniJuvix.Syntax.Universe import MiniJuvix.Syntax.Universe
import MiniJuvix.Syntax.Usage import MiniJuvix.Syntax.Usage
import Prelude (show) import Prelude (show)
@ -57,6 +59,11 @@ type family IdentifierType s = res | res -> s where
IdentifierType 'Parsed = Name IdentifierType 'Parsed = Name
IdentifierType 'Scoped = ScopedIden IdentifierType 'Scoped = ScopedIden
type HoleType :: Stage -> GHC.Type
type family HoleType s = res | res -> s where
HoleType 'Parsed = Interval
HoleType 'Scoped = Hole
type PatternAtomIdenType :: Stage -> GHC.Type type PatternAtomIdenType :: Stage -> GHC.Type
type family PatternAtomIdenType s = res | res -> s where type family PatternAtomIdenType s = res | res -> s where
PatternAtomIdenType 'Parsed = Name PatternAtomIdenType 'Parsed = Name
@ -534,11 +541,13 @@ data Expression
| ExpressionUniverse Universe | ExpressionUniverse Universe
| ExpressionLiteral LiteralLoc | ExpressionLiteral LiteralLoc
| ExpressionFunction (Function 'Scoped) | ExpressionFunction (Function 'Scoped)
| ExpressionHole (HoleType 'Scoped)
deriving stock (Show, Eq, Ord) deriving stock (Show, Eq, Ord)
instance HasAtomicity Expression where instance HasAtomicity Expression where
atomicity e = case e of atomicity e = case e of
ExpressionIdentifier {} -> Atom ExpressionIdentifier {} -> Atom
ExpressionHole {} -> Atom
ExpressionParensIdentifier {} -> Atom ExpressionParensIdentifier {} -> Atom
ExpressionApplication {} -> Aggregate appFixity ExpressionApplication {} -> Aggregate appFixity
ExpressionInfixApplication a -> Aggregate (getFixity a) ExpressionInfixApplication a -> Aggregate (getFixity a)
@ -902,6 +911,7 @@ deriving stock instance
data ExpressionAtom (s :: Stage) data ExpressionAtom (s :: Stage)
= AtomIdentifier (IdentifierType s) = AtomIdentifier (IdentifierType s)
| AtomLambda (Lambda s) | AtomLambda (Lambda s)
| AtomHole (HoleType s)
| AtomLetBlock (LetBlock s) | AtomLetBlock (LetBlock s)
| AtomUniverse Universe | AtomUniverse Universe
| AtomFunction (Function s) | AtomFunction (Function s)
@ -1004,6 +1014,7 @@ deriving stock instance
( Show (ExpressionType s), ( Show (ExpressionType s),
Show (IdentifierType s), Show (IdentifierType s),
Show (ModuleRefType s), Show (ModuleRefType s),
Show (HoleType s),
Show (SymbolType s), Show (SymbolType s),
Show (PatternType s) Show (PatternType s)
) => ) =>
@ -1012,6 +1023,7 @@ deriving stock instance
deriving stock instance deriving stock instance
( Eq (ExpressionType s), ( Eq (ExpressionType s),
Eq (IdentifierType s), Eq (IdentifierType s),
Eq (HoleType s),
Eq (ModuleRefType s), Eq (ModuleRefType s),
Eq (SymbolType s), Eq (SymbolType s),
Eq (PatternType s) Eq (PatternType s)
@ -1022,6 +1034,7 @@ deriving stock instance
( Ord (ExpressionType s), ( Ord (ExpressionType s),
Ord (IdentifierType s), Ord (IdentifierType s),
Ord (ModuleRefType s), Ord (ModuleRefType s),
Ord (HoleType s),
Ord (SymbolType s), Ord (SymbolType s),
Ord (PatternType s) Ord (PatternType s)
) => ) =>
@ -1031,6 +1044,7 @@ deriving stock instance
( Show (ExpressionType s), ( Show (ExpressionType s),
Show (IdentifierType s), Show (IdentifierType s),
Show (ModuleRefType s), Show (ModuleRefType s),
Show (HoleType s),
Show (SymbolType s), Show (SymbolType s),
Show (PatternType s) Show (PatternType s)
) => ) =>
@ -1050,6 +1064,7 @@ instance
( Eq (ExpressionType s), ( Eq (ExpressionType s),
Eq (IdentifierType s), Eq (IdentifierType s),
Eq (ModuleRefType s), Eq (ModuleRefType s),
Eq (HoleType s),
Eq (SymbolType s), Eq (SymbolType s),
Eq (PatternType s) Eq (PatternType s)
) => ) =>
@ -1061,6 +1076,7 @@ instance
( Ord (ExpressionType s), ( Ord (ExpressionType s),
Ord (IdentifierType s), Ord (IdentifierType s),
Ord (ModuleRefType s), Ord (ModuleRefType s),
Ord (HoleType s),
Ord (SymbolType s), Ord (SymbolType s),
Ord (PatternType s) Ord (PatternType s)
) => ) =>

View File

@ -146,6 +146,7 @@ allKeywords =
kwEval, kwEval,
kwForeign, kwForeign,
kwHiding, kwHiding,
kwHole,
kwImport, kwImport,
kwIn, kwIn,
kwInductive, kwInductive,
@ -275,6 +276,9 @@ kwUsing = keyword Str.using
kwWhere :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r () kwWhere :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
kwWhere = keyword Str.where_ kwWhere = keyword Str.where_
kwHole :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
kwHole = keyword Str.underscore
kwWildcard :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r () kwWildcard :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r ()
kwWildcard = keyword Str.underscore kwWildcard = keyword Str.underscore

View File

@ -185,6 +185,7 @@ expressionAtom =
<|> (AtomMatch <$> match) <|> (AtomMatch <$> match)
<|> (AtomLetBlock <$> letBlock) <|> (AtomLetBlock <$> letBlock)
<|> (AtomFunArrow <$ kwRightArrow) <|> (AtomFunArrow <$ kwRightArrow)
<|> (AtomHole <$> hole)
<|> parens (AtomParens <$> parseExpressionAtoms) <|> parens (AtomParens <$> parseExpressionAtoms)
parseExpressionAtoms :: parseExpressionAtoms ::
@ -194,6 +195,13 @@ parseExpressionAtoms = do
(_expressionAtoms, _expressionAtomsLoc) <- interval (P.some expressionAtom) (_expressionAtoms, _expressionAtomsLoc) <- interval (P.some expressionAtom)
return ExpressionAtoms {..} return ExpressionAtoms {..}
--------------------------------------------------------------------------------
-- Holes
--------------------------------------------------------------------------------
hole :: Members '[Reader ParserParams, InfoTableBuilder] r => ParsecS r (HoleType 'Parsed)
hole = snd <$> interval kwHole
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
-- Literals -- Literals
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------

View File

@ -447,14 +447,17 @@ instance PrettyCode Name where
NameUnqualified s -> ppSymbol s NameUnqualified s -> ppSymbol s
NameQualified s -> ppCode s NameQualified s -> ppCode s
nameIdSuffix :: Members '[Reader Options] r => S.NameId -> Sem r (Maybe (Doc Ann))
nameIdSuffix nid = do
showNameId <- asks (^. optShowNameId)
if
| showNameId -> Just . ("@" <>) <$> ppCode nid
| otherwise -> return Nothing
instance PrettyCode n => PrettyCode (S.Name' n) where instance PrettyCode n => PrettyCode (S.Name' n) where
ppCode S.Name' {..} = do ppCode S.Name' {..} = do
nameConcrete' <- annotateKind _nameKind <$> ppCode _nameConcrete nameConcrete' <- annotateKind _nameKind <$> ppCode _nameConcrete
showNameId <- asks (^. optShowNameId) uid <- nameIdSuffix _nameId
uid <-
if
| showNameId -> Just . ("@" <>) <$> ppCode _nameId
| otherwise -> return Nothing
return $ annSRef (nameConcrete' <?> uid) return $ annSRef (nameConcrete' <?> uid)
where where
annSRef :: Doc Ann -> Doc Ann annSRef :: Doc Ann -> Doc Ann
@ -706,6 +709,7 @@ instance PrettyCode ScopedIden where
instance PrettyCode Expression where instance PrettyCode Expression where
ppCode e = case e of ppCode e = case e of
ExpressionIdentifier n -> ppCode n ExpressionIdentifier n -> ppCode n
ExpressionHole w -> ppHole w
ExpressionParensIdentifier n -> parens <$> ppCode n ExpressionParensIdentifier n -> parens <$> ppCode n
ExpressionApplication a -> ppCode a ExpressionApplication a -> ppCode a
ExpressionInfixApplication a -> ppCode a ExpressionInfixApplication a -> ppCode a
@ -783,8 +787,18 @@ ppCodeAtom c = do
p' <- ppCode c p' <- ppCode c
return $ if isAtomic c then p' else parens p' return $ if isAtomic c then p' else parens p'
ppHole :: forall s r. (Members '[Reader Options] r, SingI s) => HoleType s -> Sem r (Doc Ann)
ppHole w = case sing :: SStage s of
SParsed -> return kwWildcard
SScoped -> ppCode w
instance PrettyCode Hole where
ppCode h = do
suff <- nameIdSuffix (h ^. holeId)
return (kwWildcard <?> suff)
instance SingI s => PrettyCode (ExpressionAtom s) where instance SingI s => PrettyCode (ExpressionAtom s) where
ppCode a = case a of ppCode = \case
AtomIdentifier n -> ppName n AtomIdentifier n -> ppName n
AtomLambda l -> ppCode l AtomLambda l -> ppCode l
AtomLetBlock lb -> ppCode lb AtomLetBlock lb -> ppCode lb
@ -794,6 +808,7 @@ instance SingI s => PrettyCode (ExpressionAtom s) where
AtomFunArrow -> return kwArrowR AtomFunArrow -> return kwArrowR
AtomMatch m -> ppCode m AtomMatch m -> ppCode m
AtomParens e -> parens <$> ppExpression e AtomParens e -> parens <$> ppExpression e
AtomHole w -> ppHole w
instance SingI s => PrettyCode (ExpressionAtoms s) where instance SingI s => PrettyCode (ExpressionAtoms s) where
ppCode as = hsep . toList <$> mapM ppCode (as ^. expressionAtoms) ppCode as = hsep . toList <$> mapM ppCode (as ^. expressionAtoms)

View File

@ -1113,9 +1113,22 @@ checkExpressionAtom e = case e of
AtomFunction fun -> AtomFunction <$> checkFunction fun AtomFunction fun -> AtomFunction <$> checkFunction fun
AtomParens par -> AtomParens <$> checkParens par AtomParens par -> AtomParens <$> checkParens par
AtomFunArrow -> return AtomFunArrow AtomFunArrow -> return AtomFunArrow
AtomHole h -> AtomHole <$> checkHole h
AtomLiteral l -> return (AtomLiteral l) AtomLiteral l -> return (AtomLiteral l)
AtomMatch match -> AtomMatch <$> checkMatch match AtomMatch match -> AtomMatch <$> checkMatch match
checkHole ::
Members '[NameIdGen] r =>
HoleType 'Parsed ->
Sem r Hole
checkHole h = do
i <- freshNameId
return
Hole
{ _holeId = i,
_holeLoc = h
}
checkParens :: checkParens ::
Members '[Error ScoperError, State Scope, State ScoperState, Reader LocalVars, InfoTableBuilder, NameIdGen] r => Members '[Error ScoperError, State Scope, State ScoperState, Reader LocalVars, InfoTableBuilder, NameIdGen] r =>
ExpressionAtoms 'Parsed -> ExpressionAtoms 'Parsed ->
@ -1306,12 +1319,21 @@ parseTerm =
parseUniverse parseUniverse
<|> parseNoInfixIdentifier <|> parseNoInfixIdentifier
<|> parseParens <|> parseParens
<|> parseHole
<|> parseFunction <|> parseFunction
<|> parseLambda <|> parseLambda
<|> parseLiteral <|> parseLiteral
<|> parseMatch <|> parseMatch
<|> parseLetBlock <|> parseLetBlock
where where
parseHole :: Parse Expression
parseHole = ExpressionHole <$> P.token lit mempty
where
lit :: ExpressionAtom 'Scoped -> Maybe Hole
lit s = case s of
AtomHole l -> Just l
_ -> Nothing
parseLiteral :: Parse Expression parseLiteral :: Parse Expression
parseLiteral = ExpressionLiteral <$> P.token lit mempty parseLiteral = ExpressionLiteral <$> P.token lit mempty
where where

View File

@ -0,0 +1,28 @@
module MiniJuvix.Syntax.Hole where
import MiniJuvix.Prelude
import MiniJuvix.Syntax.NameId
import Prettyprinter
data Hole = Hole
{ _holeId :: NameId,
_holeLoc :: Interval
}
deriving stock (Show)
makeLenses ''Hole
instance Eq Hole where
(==) = (==) `on` (^. holeId)
instance Ord Hole where
compare = compare `on` (^. holeId)
instance Hashable Hole where
hashWithSalt s = hashWithSalt s . (^. holeId)
instance HasLoc Hole where
getLoc = (^. holeLoc)
instance Pretty Hole where
pretty = const "_"

View File

@ -3,6 +3,7 @@ module MiniJuvix.Syntax.MicroJuvix.Language
module MiniJuvix.Syntax.Concrete.Scoped.Name.NameKind, module MiniJuvix.Syntax.Concrete.Scoped.Name.NameKind,
module MiniJuvix.Syntax.Concrete.Scoped.Name, module MiniJuvix.Syntax.Concrete.Scoped.Name,
module MiniJuvix.Syntax.Concrete.Loc, module MiniJuvix.Syntax.Concrete.Loc,
module MiniJuvix.Syntax.Hole,
) )
where where
@ -13,6 +14,7 @@ import MiniJuvix.Syntax.Concrete.Scoped.Name (NameId (..))
import MiniJuvix.Syntax.Concrete.Scoped.Name.NameKind import MiniJuvix.Syntax.Concrete.Scoped.Name.NameKind
import MiniJuvix.Syntax.Fixity import MiniJuvix.Syntax.Fixity
import MiniJuvix.Syntax.ForeignBlock import MiniJuvix.Syntax.ForeignBlock
import MiniJuvix.Syntax.Hole
import Prettyprinter import Prettyprinter
type FunctionName = Name type FunctionName = Name
@ -122,6 +124,7 @@ data Expression
| ExpressionApplication Application | ExpressionApplication Application
| ExpressionFunction FunctionExpression | ExpressionFunction FunctionExpression
| ExpressionLiteral LiteralLoc | ExpressionLiteral LiteralLoc
| ExpressionHole Hole
| ExpressionTyped TypedExpression | ExpressionTyped TypedExpression
deriving stock (Show) deriving stock (Show)
@ -197,6 +200,7 @@ data Type
| TypeApp TypeApplication | TypeApp TypeApplication
| TypeFunction Function | TypeFunction Function
| TypeAbs TypeAbstraction | TypeAbs TypeAbstraction
| TypeHole Hole
| TypeUniverse | TypeUniverse
| TypeAny | TypeAny
deriving stock (Eq, Show, Generic) deriving stock (Eq, Show, Generic)
@ -244,6 +248,7 @@ instance HasAtomicity Expression where
ExpressionTyped t -> atomicity (t ^. typedExpression) ExpressionTyped t -> atomicity (t ^. typedExpression)
ExpressionLiteral l -> atomicity l ExpressionLiteral l -> atomicity l
ExpressionFunction f -> atomicity f ExpressionFunction f -> atomicity f
ExpressionHole {} -> Atom
instance HasAtomicity Function where instance HasAtomicity Function where
atomicity = const (Aggregate funFixity) atomicity = const (Aggregate funFixity)
@ -256,6 +261,7 @@ instance HasAtomicity Type where
TypeIden {} -> Atom TypeIden {} -> Atom
TypeFunction f -> atomicity f TypeFunction f -> atomicity f
TypeUniverse -> Atom TypeUniverse -> Atom
TypeHole {} -> Atom
TypeAny -> Atom TypeAny -> Atom
TypeAbs a -> atomicity a TypeAbs a -> atomicity a
TypeApp a -> atomicity a TypeApp a -> atomicity a
@ -281,6 +287,7 @@ instance HasLoc Expression where
ExpressionTyped t -> getLoc (t ^. typedExpression) ExpressionTyped t -> getLoc (t ^. typedExpression)
ExpressionLiteral l -> getLoc l ExpressionLiteral l -> getLoc l
ExpressionFunction f -> getLoc f ExpressionFunction f -> getLoc f
ExpressionHole h -> getLoc h
instance HasLoc Iden where instance HasLoc Iden where
getLoc = \case getLoc = \case

View File

@ -5,6 +5,7 @@ module MiniJuvix.Syntax.MicroJuvix.Language.Extra
where where
import Data.HashMap.Strict qualified as HashMap import Data.HashMap.Strict qualified as HashMap
import Data.HashSet qualified as HashSet
import MiniJuvix.Prelude import MiniJuvix.Prelude
import MiniJuvix.Syntax.MicroJuvix.Language import MiniJuvix.Syntax.MicroJuvix.Language
@ -98,6 +99,7 @@ mkConcreteType = fmap ConcreteType . go
r' <- go r r' <- go r
return (TypeFunction (Function l' r')) return (TypeFunction (Function l' r'))
TypeAbs {} -> Nothing TypeAbs {} -> Nothing
TypeHole {} -> Nothing
TypeIden i -> case i of TypeIden i -> case i of
TypeIdenInductive {} -> return t TypeIdenInductive {} -> return t
TypeIdenAxiom {} -> return t TypeIdenAxiom {} -> return t
@ -107,6 +109,97 @@ mkConcreteType = fmap ConcreteType . go
expressionAsType' :: Expression -> Type expressionAsType' :: Expression -> Type
expressionAsType' = fromMaybe impossible . expressionAsType expressionAsType' = fromMaybe impossible . expressionAsType
findHoles :: Type -> HashSet Hole
findHoles = go
where
go :: Type -> HashSet Hole
go = \case
TypeIden {} -> mempty
TypeApp (TypeApplication a b) -> go a <> go b
TypeFunction (Function a b) -> go a <> go b
TypeAbs (TypeAbstraction _ t) -> go t
TypeHole h -> HashSet.singleton h
TypeUniverse -> mempty
TypeAny -> mempty
hasHoles :: Type -> Bool
hasHoles = not . HashSet.null . findHoles
typeAsExpression :: Type -> Expression
typeAsExpression = go
where
go :: Type -> Expression
go =
\case
TypeIden i -> ExpressionIden (goTypeIden i)
TypeApp a -> ExpressionApplication (goApp a)
TypeFunction f -> ExpressionFunction (goFunction f)
TypeAny -> error "TODO TypeAny"
TypeAbs {} -> error "TODO TypeAbs"
TypeHole h -> ExpressionHole h
TypeUniverse -> error "TODO TypeUniverse"
goTypeIden :: TypeIden -> Iden
goTypeIden = \case
TypeIdenInductive i -> IdenInductive i
TypeIdenAxiom a -> IdenAxiom a
TypeIdenVariable v -> IdenVar v
goApp :: TypeApplication -> Application
goApp (TypeApplication l r) = Application (go l) (go r)
goFunction :: Function -> FunctionExpression
goFunction (Function l r) = FunctionExpression (go l) (go r)
fillHoles :: HashMap Hole Type -> Expression -> Expression
fillHoles m = goe
where
goe :: Expression -> Expression
goe x = case x of
ExpressionIden {} -> x
ExpressionApplication a -> ExpressionApplication (goApp a)
ExpressionLiteral {} -> x
ExpressionHole h -> goHole h
ExpressionFunction f -> ExpressionFunction (goFunction f)
ExpressionTyped t ->
ExpressionTyped
( over
typedType
(fillHolesType m)
(over typedExpression goe t)
)
where
goApp :: Application -> Application
goApp (Application l r) = Application (goe l) (goe r)
goFunction :: FunctionExpression -> FunctionExpression
goFunction (FunctionExpression l r) = FunctionExpression (goe l) (goe r)
goHole :: Hole -> Expression
goHole h = case HashMap.lookup h m of
Just r -> typeAsExpression r
Nothing -> ExpressionHole h
fillHolesType :: HashMap Hole Type -> Type -> Type
fillHolesType m = go
where
go :: Type -> Type
go = \case
TypeIden i -> TypeIden i
TypeApp a -> TypeApp (goApp a)
TypeAbs a -> TypeAbs (goAbs a)
TypeFunction f -> TypeFunction (goFunction f)
TypeUniverse -> TypeUniverse
TypeAny -> TypeAny
TypeHole h -> goHole h
where
goApp :: TypeApplication -> TypeApplication
goApp (TypeApplication l r) = TypeApplication (go l) (go r)
goAbs :: TypeAbstraction -> TypeAbstraction
goAbs (TypeAbstraction v b) = TypeAbstraction v (go b)
goFunction :: Function -> Function
goFunction (Function l r) = Function (go l) (go r)
goHole :: Hole -> Type
goHole h = case HashMap.lookup h m of
Just ty -> ty
Nothing -> TypeHole h
-- | If the expression is of type TypeUniverse it should return Just. -- | If the expression is of type TypeUniverse it should return Just.
expressionAsType :: Expression -> Maybe Type expressionAsType :: Expression -> Maybe Type
expressionAsType = go expressionAsType = go
@ -117,6 +210,7 @@ expressionAsType = go
ExpressionLiteral {} -> Nothing ExpressionLiteral {} -> Nothing
ExpressionFunction f -> TypeFunction <$> goFunction f ExpressionFunction f -> TypeFunction <$> goFunction f
ExpressionTyped e -> go (e ^. typedExpression) ExpressionTyped e -> go (e ^. typedExpression)
ExpressionHole h -> Just (TypeHole h)
goFunction :: FunctionExpression -> Maybe Function goFunction :: FunctionExpression -> Maybe Function
goFunction (FunctionExpression l r) = do goFunction (FunctionExpression l r) = do
l' <- go l l' <- go l
@ -222,9 +316,10 @@ concreteTypeToExpr = go . (^. unconcreteType)
TypeAbs {} -> impossible TypeAbs {} -> impossible
TypeIden i -> ExpressionIden (goIden i) TypeIden i -> ExpressionIden (goIden i)
TypeApp (TypeApplication l r) -> ExpressionApplication (Application (go l) (go r)) TypeApp (TypeApplication l r) -> ExpressionApplication (Application (go l) (go r))
TypeFunction {} -> error "TODO" TypeFunction (Function l r) -> ExpressionFunction (FunctionExpression (go l) (go r))
TypeUniverse {} -> impossible TypeUniverse {} -> impossible
TypeAny {} -> impossible TypeAny {} -> impossible
TypeHole {} -> impossible
goIden :: TypeIden -> Iden goIden :: TypeIden -> Iden
goIden = \case goIden = \case
TypeIdenInductive n -> IdenInductive n TypeIdenInductive n -> IdenInductive n
@ -242,6 +337,7 @@ substitutionE m = go
ExpressionIden i -> goIden i ExpressionIden i -> goIden i
ExpressionApplication a -> ExpressionApplication (goApp a) ExpressionApplication a -> ExpressionApplication (goApp a)
ExpressionLiteral {} -> x ExpressionLiteral {} -> x
ExpressionHole {} -> x
ExpressionFunction f -> ExpressionFunction (goFunction f) ExpressionFunction f -> ExpressionFunction (goFunction f)
ExpressionTyped t -> ExpressionTyped (over typedExpression go t) ExpressionTyped t -> ExpressionTyped (over typedExpression go t)
goApp :: Application -> Application goApp :: Application -> Application
@ -265,6 +361,7 @@ substitution m = go
TypeFunction f -> TypeFunction (goFunction f) TypeFunction f -> TypeFunction (goFunction f)
TypeUniverse -> TypeUniverse TypeUniverse -> TypeUniverse
TypeAny -> TypeAny TypeAny -> TypeAny
TypeHole h -> TypeHole h
goApp :: TypeApplication -> TypeApplication goApp :: TypeApplication -> TypeApplication
goApp (TypeApplication l r) = TypeApplication (go l) (go r) goApp (TypeApplication l r) = TypeApplication (go l) (go r)
goAbs :: TypeAbstraction -> TypeAbstraction goAbs :: TypeAbstraction -> TypeAbstraction
@ -319,12 +416,10 @@ unfoldApplication (Application l' r') = second (|: r') (unfoldExpression l')
where where
unfoldExpression :: Expression -> (Expression, [Expression]) unfoldExpression :: Expression -> (Expression, [Expression])
unfoldExpression e = case e of unfoldExpression e = case e of
ExpressionIden {} -> (e, [])
ExpressionApplication (Application l r) -> ExpressionApplication (Application l r) ->
second (`snoc` r) (unfoldExpression l) second (`snoc` r) (unfoldExpression l)
ExpressionLiteral {} -> (e, [])
ExpressionFunction {} -> (e, [])
ExpressionTyped t -> unfoldExpression (t ^. typedExpression) ExpressionTyped t -> unfoldExpression (t ^. typedExpression)
_ -> (e, [])
unfoldTypeApplication :: TypeApplication -> (Type, NonEmpty Type) unfoldTypeApplication :: TypeApplication -> (Type, NonEmpty Type)
unfoldTypeApplication (TypeApplication l' r') = second (|: r') (unfoldType l') unfoldTypeApplication (TypeApplication l' r') = second (|: r') (unfoldType l')

View File

@ -75,6 +75,7 @@ instance PrettyCode FunctionExpression where
instance PrettyCode Expression where instance PrettyCode Expression where
ppCode = \case ppCode = \case
ExpressionIden i -> ppCode i ExpressionIden i -> ppCode i
ExpressionHole h -> ppCode h
ExpressionApplication a -> ppCode a ExpressionApplication a -> ppCode a
ExpressionTyped a -> ppCode a ExpressionTyped a -> ppCode a
ExpressionFunction f -> ppCode f ExpressionFunction f -> ppCode f
@ -119,6 +120,9 @@ kwColonColon = keyword (Str.colon <> Str.colon)
kwPipe :: Doc Ann kwPipe :: Doc Ann
kwPipe = keyword Str.pipe kwPipe = keyword Str.pipe
kwHole :: Doc Ann
kwHole = keyword Str.underscore
kwAxiom :: Doc Ann kwAxiom :: Doc Ann
kwAxiom = keyword Str.axiom kwAxiom = keyword Str.axiom
@ -167,6 +171,9 @@ instance PrettyCode FunctionArgType where
FunctionArgTypeType t -> ppCode t FunctionArgTypeType t -> ppCode t
FunctionArgTypeAbstraction v -> ppCode v FunctionArgTypeAbstraction v -> ppCode v
instance PrettyCode Hole where
ppCode _ = return kwHole
instance PrettyCode Type where instance PrettyCode Type where
ppCode = \case ppCode = \case
TypeIden i -> ppCode i TypeIden i -> ppCode i
@ -175,6 +182,7 @@ instance PrettyCode Type where
TypeAny -> return kwAny TypeAny -> return kwAny
TypeApp a -> ppCode a TypeApp a -> ppCode a
TypeAbs a -> ppCode a TypeAbs a -> ppCode a
TypeHole h -> ppCode h
instance PrettyCode InductiveConstructorDef where instance PrettyCode InductiveConstructorDef where
ppCode c = do ppCode c = do

View File

@ -14,6 +14,7 @@ import MiniJuvix.Syntax.MicroJuvix.Language.Extra
import MiniJuvix.Syntax.MicroJuvix.LocalVars import MiniJuvix.Syntax.MicroJuvix.LocalVars
import MiniJuvix.Syntax.MicroJuvix.MicroJuvixResult import MiniJuvix.Syntax.MicroJuvix.MicroJuvixResult
import MiniJuvix.Syntax.MicroJuvix.MicroJuvixTypedResult import MiniJuvix.Syntax.MicroJuvix.MicroJuvixTypedResult
import MiniJuvix.Syntax.MicroJuvix.TypeChecker.Inference
entryMicroJuvixTyped :: entryMicroJuvixTyped ::
Member (Error TypeCheckerError) r => Member (Error TypeCheckerError) r =>
@ -84,14 +85,14 @@ checkFunctionDef FunctionDef {..} = do
} }
checkExpression :: checkExpression ::
Members '[Reader InfoTable, Error TypeCheckerError, Reader LocalVars] r => Members '[Reader InfoTable, Error TypeCheckerError, Reader LocalVars, Inference] r =>
Type -> Type ->
Expression -> Expression ->
Sem r Expression Sem r Expression
checkExpression t e = do checkExpression t e = do
e' <- inferExpression' e e' <- inferExpression' e
let inferredType = e' ^. typedType let inferredType = e' ^. typedType
unless (matchTypes t inferredType) (throw (err inferredType)) unlessM (matchTypes t inferredType) (throw (err inferredType))
return (ExpressionTyped e') return (ExpressionTyped e')
where where
err infTy = err infTy =
@ -103,59 +104,8 @@ checkExpression t e = do
} }
) )
matchTypes ::
Type ->
Type ->
Bool
matchTypes a b =
isAny a || isAny b || alphaEq a b
where
isAny = \case
TypeAny -> True
_ -> False
-- | Alpha equivalence
alphaEq :: Type -> Type -> Bool
alphaEq ty = run . runReader ini . go ty
where
ini :: HashMap VarName VarName
ini = mempty
go ::
forall r.
Members '[Reader (HashMap VarName VarName)] r =>
Type ->
Type ->
Sem r Bool
go a' b' = case (a', b') of
(TypeIden a, TypeIden b) -> goIden a b
(TypeApp a, TypeApp b) -> goApp a b
(TypeAbs a, TypeAbs b) -> goAbs a b
(TypeFunction a, TypeFunction b) -> goFunction a b
(TypeUniverse, TypeUniverse) -> return True
-- TODO TypeAny should match anything?
(TypeAny, TypeAny) -> return True
-- TODO is the final wildcard bad style?
-- what if more Type constructors are added
_ -> return False
where
goIden :: TypeIden -> TypeIden -> Sem r Bool
goIden ia ib = case (ia, ib) of
(TypeIdenInductive a, TypeIdenInductive b) -> return (a == b)
(TypeIdenAxiom a, TypeIdenAxiom b) -> return (a == b)
(TypeIdenVariable a, TypeIdenVariable b) -> do
mappedEq <- (== Just b) . HashMap.lookup a <$> ask
return (a == b || mappedEq)
_ -> return False
goApp :: TypeApplication -> TypeApplication -> Sem r Bool
goApp (TypeApplication f x) (TypeApplication f' x') = andM [go f f', go x x']
goFunction :: Function -> Function -> Sem r Bool
goFunction (Function l r) (Function l' r') = andM [go l l', go r r']
goAbs :: TypeAbstraction -> TypeAbstraction -> Sem r Bool
goAbs (TypeAbstraction v1 r) (TypeAbstraction v2 r') =
local (HashMap.insert v1 v2) (go r r')
inferExpression :: inferExpression ::
Members '[Reader InfoTable, Error TypeCheckerError, Reader LocalVars] r => Members '[Reader InfoTable, Error TypeCheckerError, Reader LocalVars, Inference] r =>
Expression -> Expression ->
Sem r Expression Sem r Expression
inferExpression = fmap ExpressionTyped . inferExpression' inferExpression = fmap ExpressionTyped . inferExpression'
@ -190,6 +140,15 @@ constructorArgTypes i =
i ^. constructorInfoArgs i ^. constructorInfoArgs
) )
checkFunctionClauseBody ::
Members '[Reader InfoTable, Error TypeCheckerError] r =>
LocalVars ->
Type ->
Expression ->
Sem r Expression
checkFunctionClauseBody locals expectedTy body =
runInference (runReader locals (checkExpression expectedTy body))
checkFunctionClause :: checkFunctionClause ::
Members '[Reader InfoTable, Error TypeCheckerError] r => Members '[Reader InfoTable, Error TypeCheckerError] r =>
FunctionInfo -> FunctionInfo ->
@ -210,8 +169,7 @@ checkFunctionClause info clause@FunctionClause {..} = do
(locals ^. localTyMap) (locals ^. localTyMap)
) )
bodyTy bodyTy
_clauseBody' <- _clauseBody' <- checkFunctionClauseBody locals bodyTy' _clauseBody
runReader locals (checkExpression bodyTy' _clauseBody)
return return
FunctionClause FunctionClause
{ _clauseBody = _clauseBody', { _clauseBody = _clauseBody',
@ -310,7 +268,7 @@ checkPattern funName = go
inferExpression' :: inferExpression' ::
forall r. forall r.
Members '[Reader InfoTable, Reader LocalVars, Error TypeCheckerError] r => Members '[Reader InfoTable, Reader LocalVars, Error TypeCheckerError, Inference] r =>
Expression -> Expression ->
Sem r TypedExpression Sem r TypedExpression
inferExpression' e = case e of inferExpression' e = case e of
@ -319,6 +277,7 @@ inferExpression' e = case e of
ExpressionTyped t -> return t ExpressionTyped t -> return t
ExpressionLiteral l -> goLiteral l ExpressionLiteral l -> goLiteral l
ExpressionFunction f -> goExpressionFunction f ExpressionFunction f -> goExpressionFunction f
ExpressionHole h -> freshMetavar h
where where
goExpressionFunction :: FunctionExpression -> Sem r TypedExpression goExpressionFunction :: FunctionExpression -> Sem r TypedExpression
goExpressionFunction (FunctionExpression l r) = do goExpressionFunction (FunctionExpression l r) = do
@ -412,8 +371,4 @@ viewTypeApp :: Type -> (Type, [Type])
viewTypeApp t = case t of viewTypeApp t = case t of
TypeApp (TypeApplication l r) -> TypeApp (TypeApplication l r) ->
second (`snoc` r) (viewTypeApp l) second (`snoc` r) (viewTypeApp l)
TypeAny {} -> (t, []) _ -> (t, [])
TypeUniverse {} -> (t, [])
TypeAbs {} -> (t, [])
TypeFunction {} -> (t, [])
TypeIden {} -> (t, [])

View File

@ -0,0 +1,160 @@
module MiniJuvix.Syntax.MicroJuvix.TypeChecker.Inference where
import Data.HashMap.Strict qualified as HashMap
import MiniJuvix.Prelude hiding (fromEither)
import MiniJuvix.Syntax.MicroJuvix.Error
import MiniJuvix.Syntax.MicroJuvix.Language.Extra
data MetavarState
= Fresh
| -- | Type may contain holes
Refined Type
data Inference m a where
FreshMetavar :: Hole -> Inference m TypedExpression
MatchTypes :: Type -> Type -> Inference m Bool
makeSem ''Inference
newtype InferenceState = InferenceState
{ _inferenceMap :: HashMap Hole MetavarState
}
makeLenses ''InferenceState
iniState :: InferenceState
iniState = InferenceState mempty
closeState :: Member (Error TypeCheckerError) r => InferenceState -> Sem r (HashMap Hole Type)
closeState = \case
InferenceState m -> execState mempty (f m)
where
f ::
forall r'.
Members '[Error TypeCheckerError, State (HashMap Hole Type)] r' =>
HashMap Hole MetavarState ->
Sem r' ()
f m = mapM_ (uncurry goHole) (HashMap.toList m)
where
goHole :: Hole -> MetavarState -> Sem r' Type
goHole h = \case
Fresh -> throw @TypeCheckerError (error "unsolved meta")
Refined t -> do
s <- gets @(HashMap Hole Type) (^. at h)
case s of
Just noHolesTy -> return noHolesTy
Nothing -> do
x <- goType t
modify (HashMap.insert h x)
return x
goType :: Type -> Sem r' Type
goType t = case t of
TypeIden {} -> return t
TypeApp (TypeApplication a b) -> do
a' <- goType a
b' <- goType b
return (TypeApp (TypeApplication a' b'))
TypeFunction (Function a b) -> do
a' <- goType a
b' <- goType b
return (TypeFunction (Function a' b'))
TypeAbs (TypeAbstraction v b) -> TypeAbs . TypeAbstraction v <$> goType b
TypeUniverse -> return TypeUniverse
TypeAny -> return TypeAny
TypeHole h' ->
let st = fromJust (m ^. at h')
in goHole h' st
getMetavar :: Member (State InferenceState) r => Hole -> Sem r MetavarState
getMetavar h = gets (fromJust . (^. inferenceMap . at h))
re :: Member (Error TypeCheckerError) r => Sem (Inference ': r) Expression -> Sem (State InferenceState ': r) Expression
re = reinterpret $ \case
FreshMetavar h -> freshMetavar' h
MatchTypes a b -> matchTypes' a b
where
queryMetavar' :: Members '[State InferenceState] r => Hole -> Sem r (Maybe Type)
queryMetavar' h = metavarType <$> getMetavar h
freshMetavar' :: Members '[State InferenceState] r => Hole -> Sem r TypedExpression
freshMetavar' h = do
modify (over inferenceMap (HashMap.insert h Fresh))
return
TypedExpression
{ _typedExpression = ExpressionHole h,
_typedType = TypeUniverse
}
refineMetavar' ::
Members '[Error TypeCheckerError, State InferenceState] r =>
Hole ->
Type ->
Sem r ()
refineMetavar' h t = do
s <- gets (fromJust . (^. inferenceMap . at h))
case s of
Fresh -> modify (over inferenceMap (HashMap.insert h (Refined t)))
Refined r -> goRefine r t
goRefine :: Members '[Error TypeCheckerError, State InferenceState] r => Type -> Type -> Sem r ()
goRefine r t = do
eq <- matchTypes' r t
unless eq (error "type error: cannot match types")
metavarType :: MetavarState -> Maybe Type
metavarType = \case
Fresh -> Nothing
Refined t -> Just t
-- Supports alpha equivalence.
matchTypes' :: Members '[Error TypeCheckerError, State InferenceState] r => Type -> Type -> Sem r Bool
matchTypes' ty = runReader ini . go ty
where
ini :: HashMap VarName VarName
ini = mempty
go ::
forall r.
Members '[Error TypeCheckerError, State InferenceState, Reader (HashMap VarName VarName)] r =>
Type ->
Type ->
Sem r Bool
go a' b' = case (a', b') of
(TypeIden a, TypeIden b) -> goIden a b
(TypeApp a, TypeApp b) -> goApp a b
(TypeAbs a, TypeAbs b) -> goAbs a b
(TypeFunction a, TypeFunction b) -> goFunction a b
(TypeUniverse, TypeUniverse) -> return True
(TypeAny, _) -> return True
(_, TypeAny) -> return True
(TypeHole h, a) -> goHole h a
(a, TypeHole h) -> goHole h a
-- TODO is the final wildcard bad style?
-- what if more Type constructors are added
_ -> return False
where
goHole :: Hole -> Type -> Sem r Bool
goHole h t = do
r <- queryMetavar' h
case r of
Nothing -> refineMetavar' h t $> True
Just ht -> matchTypes' t ht
goIden :: TypeIden -> TypeIden -> Sem r Bool
goIden ia ib = case (ia, ib) of
(TypeIdenInductive a, TypeIdenInductive b) -> return (a == b)
(TypeIdenAxiom a, TypeIdenAxiom b) -> return (a == b)
(TypeIdenVariable a, TypeIdenVariable b) -> do
mappedEq <- (== Just b) . HashMap.lookup a <$> ask
return (a == b || mappedEq)
_ -> return False
goApp :: TypeApplication -> TypeApplication -> Sem r Bool
goApp (TypeApplication f x) (TypeApplication f' x') = andM [go f f', go x x']
goFunction :: Function -> Function -> Sem r Bool
goFunction (Function l r) (Function l' r') = andM [go l l', go r r']
goAbs :: TypeAbstraction -> TypeAbstraction -> Sem r Bool
goAbs (TypeAbstraction v1 r) (TypeAbstraction v2 r') =
local (HashMap.insert v1 v2) (go r r')
runInference :: Member (Error TypeCheckerError) r => Sem (Inference ': r) Expression -> Sem r Expression
runInference a = do
(subs, expr) <- runState iniState (re a) >>= firstM closeState
return (fillHoles subs expr)

View File

@ -94,6 +94,7 @@ checkExpression e =
ExpressionApplication a -> checkApplication a ExpressionApplication a -> checkApplication a
ExpressionFunction f -> checkFunction f ExpressionFunction f -> checkFunction f
ExpressionIden {} -> return () ExpressionIden {} -> return ()
ExpressionHole {} -> return ()
ExpressionUniverse {} -> return () ExpressionUniverse {} -> return ()
ExpressionLiteral {} -> return () ExpressionLiteral {} -> return ()

View File

@ -215,6 +215,7 @@ goType e = case e of
Abstract.ExpressionApplication a -> TypeApp <$> goTypeApplication a Abstract.ExpressionApplication a -> TypeApp <$> goTypeApplication a
Abstract.ExpressionFunction f -> goFunction f Abstract.ExpressionFunction f -> goFunction f
Abstract.ExpressionLiteral {} -> unsupported "literals in types" Abstract.ExpressionLiteral {} -> unsupported "literals in types"
Abstract.ExpressionHole h -> return (TypeHole h)
goApplication :: Abstract.Application -> Sem r Application goApplication :: Abstract.Application -> Sem r Application
goApplication (Abstract.Application f x) = do goApplication (Abstract.Application f x) = do
@ -249,6 +250,7 @@ goExpression e = case e of
Abstract.ExpressionFunction f -> ExpressionFunction <$> goExpressionFunction f Abstract.ExpressionFunction f -> ExpressionFunction <$> goExpressionFunction f
Abstract.ExpressionApplication a -> ExpressionApplication <$> goApplication a Abstract.ExpressionApplication a -> ExpressionApplication <$> goApplication a
Abstract.ExpressionLiteral l -> return (ExpressionLiteral l) Abstract.ExpressionLiteral l -> return (ExpressionLiteral l)
Abstract.ExpressionHole h -> return (ExpressionHole h)
goInductiveParameter :: Abstract.FunctionParameter -> Sem r InductiveParameter goInductiveParameter :: Abstract.FunctionParameter -> Sem r InductiveParameter
goInductiveParameter f = goInductiveParameter f =
@ -302,6 +304,7 @@ viewConstructorType :: Abstract.Expression -> Sem r ([Type], Type)
viewConstructorType e = case e of viewConstructorType e = case e of
Abstract.ExpressionFunction f -> first toList <$> viewFunctionType f Abstract.ExpressionFunction f -> first toList <$> viewFunctionType f
Abstract.ExpressionIden i -> return ([], TypeIden (goTypeIden i)) Abstract.ExpressionIden i -> return ([], TypeIden (goTypeIden i))
Abstract.ExpressionHole {} -> unsupported "holes in constructor type"
Abstract.ExpressionApplication a -> do Abstract.ExpressionApplication a -> do
a' <- goTypeApplication a a' <- goTypeApplication a
return ([], TypeApp a') return ([], TypeApp a')

View File

@ -292,6 +292,7 @@ goExpression = go
Micro.ExpressionTyped t -> go (t ^. Micro.typedExpression) Micro.ExpressionTyped t -> go (t ^. Micro.typedExpression)
Micro.ExpressionApplication a -> goApp a Micro.ExpressionApplication a -> goApp a
Micro.ExpressionFunction {} -> impossible Micro.ExpressionFunction {} -> impossible
Micro.ExpressionHole {} -> impossible
goApp :: Micro.Application -> Sem r Expression goApp :: Micro.Application -> Sem r Expression
goApp a = do goApp a = do
let (f, args) = Micro.unfoldApplication a let (f, args) = Micro.unfoldApplication a
@ -499,6 +500,7 @@ goType = go . (^. Micro.unconcreteType)
Micro.TypeAny -> return TypeAny Micro.TypeAny -> return TypeAny
Micro.TypeUniverse -> return TypeUniverse Micro.TypeUniverse -> return TypeUniverse
Micro.TypeAbs {} -> impossible Micro.TypeAbs {} -> impossible
Micro.TypeHole {} -> impossible
Micro.TypeFunction f -> TypeFunction <$> goFunction f Micro.TypeFunction f -> TypeFunction <$> goFunction f
Micro.TypeApp a -> goApp a Micro.TypeApp a -> goApp a
goApp :: Micro.TypeApplication -> Sem r Type goApp :: Micro.TypeApplication -> Sem r Type

View File

@ -97,6 +97,7 @@ goType = \case
TypeIden {} -> return () TypeIden {} -> return ()
TypeApp a -> goTypeApplication a TypeApp a -> goTypeApplication a
TypeAny -> return () TypeAny -> return ()
TypeHole {} -> impossible
TypeUniverse -> return () TypeUniverse -> return ()
TypeFunction f -> goFunction f TypeFunction f -> goFunction f
TypeAbs a -> goTypeAbstraction a TypeAbs a -> goTypeAbstraction a
@ -115,6 +116,7 @@ goExpression = \case
ExpressionApplication a -> goApplication a ExpressionApplication a -> goApplication a
ExpressionFunction a -> goFunctionExpression a ExpressionFunction a -> goFunctionExpression a
ExpressionLiteral {} -> return () ExpressionLiteral {} -> return ()
ExpressionHole {} -> impossible
ExpressionTyped t -> do ExpressionTyped t -> do
goType (t ^. typedType) goType (t ^. typedType)
goExpression (t ^. typedExpression) goExpression (t ^. typedExpression)

View File

@ -182,12 +182,13 @@ goExpression = \case
ExpressionApplication a -> A.ExpressionApplication <$> goApplication a ExpressionApplication a -> A.ExpressionApplication <$> goApplication a
ExpressionInfixApplication ia -> A.ExpressionApplication <$> goInfix ia ExpressionInfixApplication ia -> A.ExpressionApplication <$> goInfix ia
ExpressionPostfixApplication pa -> A.ExpressionApplication <$> goPostfix pa ExpressionPostfixApplication pa -> A.ExpressionApplication <$> goPostfix pa
ExpressionLiteral l -> return $ A.ExpressionLiteral l ExpressionLiteral l -> return (A.ExpressionLiteral l)
ExpressionLambda {} -> unsupported "Lambda" ExpressionLambda {} -> unsupported "Lambda"
ExpressionMatch {} -> unsupported "Match" ExpressionMatch {} -> unsupported "Match"
ExpressionLetBlock {} -> unsupported "Let Block" ExpressionLetBlock {} -> unsupported "Let Block"
ExpressionUniverse uni -> return $ A.ExpressionUniverse (goUniverse uni) ExpressionUniverse uni -> return $ A.ExpressionUniverse (goUniverse uni)
ExpressionFunction func -> A.ExpressionFunction <$> goFunction func ExpressionFunction func -> A.ExpressionFunction <$> goFunction func
ExpressionHole h -> return (A.ExpressionHole h)
where where
goIden :: C.ScopedIden -> A.Expression goIden :: C.ScopedIden -> A.Expression
goIden x = A.ExpressionIden $ case x of goIden x = A.ExpressionIden $ case x of

View File

@ -125,5 +125,6 @@ tests =
PosTest "Inductive types and pattern matching" "Nat", PosTest "Inductive types and pattern matching" "Nat",
PosTest "Polymorphic types" "Polymorphism", PosTest "Polymorphic types" "Polymorphism",
PosTest "Multiple modules" "MultiModules", PosTest "Multiple modules" "MultiModules",
PosTest "Higher Order Functions" "HigherOrder" PosTest "Higher Order Functions" "HigherOrder",
PosTest "Higher Order Functions and explicit holes" "PolymorphismHoles"
] ]

View File

@ -38,5 +38,9 @@ tests =
PosTest PosTest
"Polymorphic Simple Fungible Token" "Polymorphic Simple Fungible Token"
"FullExamples" "FullExamples"
"PolySimpleFungibleToken.mjuvix" "PolySimpleFungibleToken.mjuvix",
PosTest
"Polymorphism and higher rank functions with explicit holes"
"."
"PolymorphismHoles.mjuvix"
] ]

View File

@ -47,6 +47,10 @@ tests =
"GHC backend Hello World" "GHC backend Hello World"
"MiniHaskell" "MiniHaskell"
"HelloWorld.mjuvix", "HelloWorld.mjuvix",
PosTest
"PolySimpleFungibleToken with explicit holes"
"FullExamples"
"PolySimpleFungibleTokenHoles.mjuvix",
PosTest PosTest
"GHC backend MonoSimpleFungibleToken" "GHC backend MonoSimpleFungibleToken"
"FullExamples" "FullExamples"
@ -66,5 +70,9 @@ tests =
PosTest PosTest
"Polymorphism and higher rank functions" "Polymorphism and higher rank functions"
"." "."
"Polymorphism.mjuvix" "Polymorphism.mjuvix",
PosTest
"Polymorphism and higher rank functions with explicit holes"
"."
"PolymorphismHoles.mjuvix"
] ]

View File

@ -0,0 +1,303 @@
module PolySimpleFungibleTokenHoles;
foreign ghc {
import Anoma
};
--------------------------------------------------------------------------------
-- Booleans
--------------------------------------------------------------------------------
inductive Bool {
true : Bool;
false : Bool;
};
infixr 2 ||;
|| : Bool → Bool → Bool;
|| false a ≔ a;
|| true _ ≔ true;
infixr 3 &&;
&& : Bool → Bool → Bool;
&& false _ ≔ false;
&& true a ≔ a;
if : (A : Type) → Bool → A → A → A;
if _ true a _ ≔ a;
if _ false _ b ≔ b;
--------------------------------------------------------------------------------
-- Backend Booleans
--------------------------------------------------------------------------------
axiom BackendBool : Type;
compile BackendBool {
ghc ↦ "Bool";
};
axiom backend-true : BackendBool;
compile backend-true {
ghc ↦ "True";
};
axiom backend-false : BackendBool;
compile backend-false {
ghc ↦ "False";
};
--------------------------------------------------------------------------------
-- Backend Bridge
--------------------------------------------------------------------------------
foreign ghc {
bool :: Bool -> a -> a -> a
bool True x _ = x
bool False _ y = y
};
axiom bool : BackendBool → Bool → Bool → Bool;
compile bool {
ghc ↦ "bool";
};
from-backend-bool : BackendBool → Bool;
from-backend-bool bb ≔ bool bb true false;
--------------------------------------------------------------------------------
-- Functions
--------------------------------------------------------------------------------
const : (A : Type) → (B : Type) → A → B → A;
const _ _ a _ ≔ a;
id : (A : Type) → A → A;
id _ a ≔ a;
--------------------------------------------------------------------------------
-- Integers
--------------------------------------------------------------------------------
axiom Int : Type;
compile Int {
ghc ↦ "Int";
};
infix 4 <';
axiom <' : Int → Int → BackendBool;
compile <' {
ghc ↦ "(<)";
};
infix 4 <;
< : Int → Int → Bool;
< i1 i2 ≔ from-backend-bool (i1 <' i2);
axiom eqInt : Int → Int → BackendBool;
compile eqInt {
ghc ↦ "(==)";
};
infix 4 ==Int;
==Int : Int → Int → Bool;
==Int i1 i2 ≔ from-backend-bool (eqInt i1 i2);
infixl 6 -;
axiom - : Int -> Int -> Int;
compile - {
ghc ↦ "(-)";
};
infixl 6 +;
axiom + : Int -> Int -> Int;
compile + {
ghc ↦ "(+)";
};
--------------------------------------------------------------------------------
-- Strings
--------------------------------------------------------------------------------
axiom String : Type;
compile String {
ghc ↦ "[Char]";
};
axiom eqString : String → String → BackendBool;
compile eqString {
ghc ↦ "(==)";
};
infix 4 ==String;
==String : String → String → Bool;
==String s1 s2 ≔ from-backend-bool (eqString s1 s2);
--------------------------------------------------------------------------------
-- Lists
--------------------------------------------------------------------------------
inductive List (A : Type) {
nil : List A;
cons : A → List A → List A;
};
elem : (A : Type) → (A → A → Bool) → A → List A → Bool;
elem _ _ _ nil ≔ false;
elem _ eq s (cons x xs) ≔ eq s x || elem _ eq s xs;
foldl : (A : Type) → (B : Type) → (B → A → B) → B → List A → B;
foldl _ _ f z nil ≔ z;
foldl _ _ f z (cons h hs) ≔ foldl _ _ f (f z h) hs;
--------------------------------------------------------------------------------
-- Pair
--------------------------------------------------------------------------------
inductive Pair (A : Type) (B : Type) {
mkPair : A → B → Pair A B;
};
--------------------------------------------------------------------------------
-- Maybe
--------------------------------------------------------------------------------
inductive Maybe (A : Type) {
nothing : Maybe A;
just : A → Maybe A;
};
from-int : Int → Maybe Int;
from-int i ≔ if _ (i < 0) (nothing _) (just _ i);
maybe : (A : Type) → (B : Type) → B → (A → B) → Maybe A → B;
maybe _ _ b _ nothing ≔ b;
maybe _ _ _ f (just x) ≔ f x;
from-string : String → Maybe String;
from-string s ≔ if _ (s ==String "") (nothing _) (just _ s);
pair-from-optionString : (String → Pair Int Bool) → Maybe String → Pair Int Bool;
pair-from-optionString ≔ maybe _ _ (mkPair _ _ 0 false);
--------------------------------------------------------------------------------
-- Anoma
--------------------------------------------------------------------------------
axiom readPre : String → Int;
compile readPre {
ghc ↦ "readPre";
};
axiom readPost : String → Int;
compile readPost {
ghc ↦ "readPost";
};
axiom isBalanceKey : String → String → String;
compile isBalanceKey {
ghc ↦ "isBalanceKey";
};
read-pre : String → Maybe Int;
read-pre s ≔ from-int (readPre s);
read-post : String → Maybe Int;
read-post s ≔ from-int (readPost s);
is-balance-key : String → String → Maybe String;
is-balance-key token key ≔ from-string (isBalanceKey token key);
unwrap-default : Maybe Int → Int;
unwrap-default o ≔ maybe _ _ 0 (id _) o;
--------------------------------------------------------------------------------
-- Validity Predicate
--------------------------------------------------------------------------------
change-from-key : String → Int;
change-from-key key ≔ unwrap-default (read-post key) - unwrap-default (read-pre key);
check-vp : List String → String → Int → String → Pair Int Bool;
check-vp verifiers key change owner ≔
if _
(change-from-key key < 0)
-- make sure the spender approved the transaction
(mkPair _ _ (change + (change-from-key key)) (elem _ (==String) owner verifiers))
(mkPair _ _ (change + (change-from-key key)) true);
check-keys : String → List String → Pair Int Bool → String → Pair Int Bool;
check-keys token verifiers (mkPair change is-success) key ≔
if _
is-success
(pair-from-optionString (check-vp verifiers key change) (is-balance-key token key))
(mkPair _ _ 0 false);
check-result : Pair Int Bool → Bool;
check-result (mkPair change all-checked) ≔ (change ==Int 0) && all-checked;
vp : String → List String → List String → Bool;
vp token keys-changed verifiers ≔
check-result
(foldl _ _
(check-keys token verifiers)
(mkPair _ _ 0 true)
keys-changed);
--------------------------------------------------------------------------------
-- IO
--------------------------------------------------------------------------------
axiom Action : Type;
compile Action {
ghc ↦ "IO ()";
};
axiom putStr : String → Action;
compile putStr {
ghc ↦ "putStr";
};
axiom putStrLn : String → Action;
compile putStrLn {
ghc ↦ "putStrLn";
};
infixl 1 >>;
axiom >> : Action → Action → Action;
compile >> {
ghc ↦ "(>>)";
};
show-result : Bool → String;
show-result true ≔ "OK";
show-result false ≔ "FAIL";
--------------------------------------------------------------------------------
-- Testing VP
--------------------------------------------------------------------------------
token : String;
token ≔ "owner-token";
owner-address : String;
owner-address ≔ "owner-address";
change1-key : String;
change1-key ≔ "change1-key";
change2-key : String;
change2-key ≔ "change2-key";
verifiers : List String;
verifiers ≔ cons _ owner-address (nil _);
keys-changed : List String;
keys-changed ≔ cons _ change1-key (cons _ change2-key (nil _));
main : Action;
main ≔
(putStr "VP Status: ")
>> (putStrLn (show-result (vp token keys-changed verifiers)));
end;

View File

@ -0,0 +1,89 @@
module Input;
--------------------------------------------------------------------------------
-- Booleans
--------------------------------------------------------------------------------
inductive Bool {
true : Bool;
false : Bool;
};
--------------------------------------------------------------------------------
-- Strings
--------------------------------------------------------------------------------
axiom String : Type;
compile String {
ghc ↦ "[Char]";
c ↦ "char*";
};
--------------------------------------------------------------------------------
-- IO
--------------------------------------------------------------------------------
axiom Action : Type;
compile Action {
ghc ↦ "IO ()";
c ↦ "int";
};
foreign c {
int sequence(int a, int b) {
return a + b;
\}
};
infixl 1 >>;
axiom >> : Action → Action → Action;
compile >> {
ghc ↦ "(>>)";
c ↦ "sequence";
};
axiom put-str : String → Action;
compile put-str {
ghc ↦ "putStr";
c ↦ "putStr";
};
axiom put-str-ln : String → Action;
compile put-str-ln {
ghc ↦ "putStrLn";
c ↦ "putStrLn";
};
bool-to-str : Bool → String;
bool-to-str true ≔ "True";
bool-to-str false ≔ "False";
--------------------------------------------------------------------------------
-- Pair
--------------------------------------------------------------------------------
inductive Pair (A : Type) (B : Type) {
mkPair : A → B → Pair A B;
};
fst : (A : Type) → (B : Type) → Pair A B → A;
fst _ _ (mkPair a b) ≔ a;
--------------------------------------------------------------------------------
-- Main
--------------------------------------------------------------------------------
fst-of-pair : Action;
fst-of-pair ≔ (put-str "fst (True, False) = ")
>> put-str-ln (bool-to-str (fst _ _ (mkPair _ _ true false)));
main : Action;
main ≔ fst-of-pair;
end;

View File

@ -0,0 +1 @@
fst (True, False) = True

View File

@ -0,0 +1,105 @@
module PolymorphismHoles;
inductive Pair (A : Type) (B : Type) {
mkPair : A → B → Pair A B;
};
inductive Nat {
zero : Nat;
suc : Nat → Nat;
};
inductive List (A : Type) {
nil : List A;
-- TODO check that the return type is saturated with the proper variable
cons : A → List A → Nat;
};
inductive Bool {
false : Bool;
true : Bool;
};
id : (A : Type) → A → A;
id _ a ≔ a;
terminating
undefined : (A : Type) → A;
undefined A ≔ undefined A;
add : Nat → Nat → Nat;
add zero b ≔ b;
add (suc a) b ≔ suc (add a b);
nil' : (E : Type) → List E;
nil' A ≔ nil _;
-- currying
nil'' : (E : Type) → List E;
nil'' ≔ nil;
fst : (A : Type) → (B : Type) → Pair A B → A;
fst _ _ (mkPair a b) ≔ a;
p : Pair Bool Bool;
p ≔ mkPair _ _ true false;
swap : (A : Type) → (B : Type) → Pair A B → Pair B A;
swap A B (mkPair a b) ≔ mkPair _ _ b a;
curry : (A : Type) → (B : Type) → (C : Type)
→ (Pair A B → C) → A → B → C;
curry A B C f a b ≔ f (mkPair _ _ a b) ;
ap : (A : Type) → (B : Type)
→ (A → B) → A → B;
ap A B f a ≔ f a;
headDef : (A : Type) → A → List A → A;
headDef _ d nil ≔ d;
headDef A _ (cons h _) ≔ h;
ite : (A : Type) → Bool → A → A → A;
ite _ true tt _ ≔ tt;
ite _ false _ ff ≔ ff;
filter : (A : Type) → (A → Bool) → List A → List A;
filter _ f nil ≔ nil _;
filter _ f (cons x xs) ≔ ite _ (f x) (cons _ x (filter _ f xs)) (filter _ f xs);
map : (A : Type) → (B : Type) →
(A → B) → List A → List B;
map _ _ f nil ≔ nil _;
map _ _ f (cons x xs) ≔ cons _ (f x) (map _ _ f xs);
zip : (A : Type) → (B : Type)
→ List A → List B → List (Pair A B);
zip A _ nil _ ≔ nil _;
zip _ _ _ nil ≔ nil _;
zip _ _ (cons a as) (cons b bs) ≔ nil _;
zipWith : (A : Type) → (B : Type) → (C : Type)
→ (A → B → C)
→ List A → List B → List C;
zipWith _ _ C f nil _ ≔ nil C;
zipWith _ _ C f _ nil ≔ nil C;
zipWith _ _ _ f (cons a as) (cons b bs) ≔ cons _ (f a b) (zipWith _ _ _ f as bs);
rankn : ((A : Type) → A → A) → Bool → Nat → Pair Bool Nat;
rankn f b n ≔ mkPair _ _ (f _ b) (f _ n);
-- currying
trankn : Pair Bool Nat;
trankn ≔ rankn id false zero;
l1 : List Nat;
l1 ≔ cons _ zero (nil _);
pairEval : (A : Type) → (B : Type) → Pair (A → B) A → B;
pairEval _ _ (mkPair f x) ≔ f x;
main : Nat;
main ≔ headDef _ (pairEval _ _ (mkPair _ _ (add zero) zero))
(zipWith _ _ _ add l1 l1);
end;