Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
196 commits
Select commit Hold shift + click to select a range
04c52ac
Add "hoping" variables
croyzor Aug 19, 2024
3a1d6fe
Expand Free monad with Define and Yield
croyzor Aug 19, 2024
bf6cfcf
Add Define/Yield cases to handler functions
croyzor Aug 20, 2024
a6f00dd
Handle Yield in toplevel handler
croyzor Aug 20, 2024
4204c50
Add bang parsing
mark-koch Aug 20, 2024
3b8fdc1
Turn on ApplicativeDo
croyzor Aug 20, 2024
8f904bc
Add some dummy code for typechecking !
croyzor Aug 20, 2024
8b852a2
Revert "Add "hoping" variables"
croyzor Aug 20, 2024
77b92fe
Some parallelisation
croyzor Aug 20, 2024
3a1288d
Add hope set to monad
croyzor Aug 20, 2024
b979c70
Move occur check logic to Eval
croyzor Aug 20, 2024
a197fb2
misc changes
croyzor Aug 20, 2024
b115f84
[broken] update eqworker
croyzor Aug 20, 2024
ce1d1cf
Revert "[broken] update eqworker"
croyzor Aug 20, 2024
c064466
Add !,! test
croyzor Aug 20, 2024
b33f100
Rewrite typeEq
mark-koch Aug 20, 2024
c093ced
feat: Solve numbers that are just variables
croyzor Aug 21, 2024
7986539
typeEqRow returns sub-problems
acl-cqc Aug 21, 2024
7afa2c4
sequence_ -> traverse_ id
acl-cqc Aug 21, 2024
265a5b6
[broken] Build things to wire into solved hopes
croyzor Aug 21, 2024
2a360b6
Don't hide that error
croyzor Aug 21, 2024
6be252b
Fix typechecking for infer example
croyzor Aug 22, 2024
646f6f9
feat: Complain when we have remaining Nat-kinded holes
croyzor Aug 22, 2024
c2c8bbe
Incude file context in hopeSet
croyzor Aug 22, 2024
3765a8a
Allow comparing VInx
croyzor Aug 22, 2024
a22531b
Rewrite dynamic num refinements to work on srcs and tgts
croyzor Aug 22, 2024
af75834
Fix demandEven logic
croyzor Aug 22, 2024
283ccae
Flip that hypo node back around
croyzor Aug 22, 2024
0da9554
Rewrite computeMeta to do definition as well
croyzor Aug 23, 2024
2139140
SolvePatterns build fixes; unified.brat+infer.brat fail with non-clos…
acl-cqc Sep 17, 2024
78cc87c
Step0. Yield in getThunks
acl-cqc Aug 21, 2024
fb99b1a
Drop already-commented-out Helpers.hs export list
acl-cqc Sep 20, 2024
07c17ed
WIP two-stage check
acl-cqc Aug 21, 2024
23853e5
Add infer_thunks(,2).brat example; ...2 works but map body not checked
acl-cqc Aug 21, 2024
75e9017
checkClause returns subproblem (oops) - BOTH infer_thunks(,2) failing…
acl-cqc Sep 20, 2024
0f21ce7
Revert "checkClause returns subproblem (oops) - BOTH infer_thunks(,2)…
acl-cqc Sep 20, 2024
3bebd4c
WIP debug (shows we stop at [to_float] and never check to_float)
acl-cqc Aug 21, 2024
dce7f0f
Try just using *> rather than returning subproblem (tests build, 59 f…
acl-cqc Sep 17, 2024
5764083
WIP add request to Fork, but TODO captureOuterLocals (tests build but…
acl-cqc Sep 17, 2024
a2ebfcf
Add captureSets, AddCapture
acl-cqc Sep 17, 2024
2e4b14e
Plumb captureSet into CompilationState (never read), various Load.hs …
acl-cqc Sep 17, 2024
85ff9c7
captureOuterLocals routes captures via AddCapture, so Box VEnv always…
acl-cqc Aug 23, 2024
c90845c
And remove VEnv from Box
acl-cqc Aug 23, 2024
115c0fa
wip debug
acl-cqc Aug 23, 2024
c24ca0d
new: Add `Lluf` operation to the BRAT hugr extension
croyzor Sep 25, 2024
672392c
checkpoint b4 I break eerything
croyzor Sep 25, 2024
9f3faa8
A couple of unit tests with Fork/Define/Yield (add assertCheckingFail)
acl-cqc Aug 23, 2024
e694a8d
Reduce change, revert checkInputs/Outputs back to Checking, also chec…
acl-cqc Sep 17, 2024
2b73543
Add string description to Fork
acl-cqc Oct 1, 2024
251455b
TEMP remove failure tests
acl-cqc Sep 13, 2024
47f4c31
Fork outside Req, with both child computations (44 fails)
acl-cqc Oct 1, 2024
9dc4b0e
WIP remove debug
acl-cqc Oct 1, 2024
554bae2
Fix compilation crashing on empty captureSet
acl-cqc Sep 18, 2024
0bfcc27
Add isSkolem func, use in typeEqEta - TODO for now True for any outport
acl-cqc Sep 18, 2024
a4115fb
simpleCheck is Checking, allow to define hopes (except nat/int?!) and…
acl-cqc Sep 18, 2024
3b76be2
typeMap stores skolem-ness (always False ATM); TypeOf returns (EndTyp…
acl-cqc Sep 17, 2024
2ebb941
Inline only use of declareSrc
acl-cqc Sep 17, 2024
e0c7997
Declare takes Bool param (still always False)
acl-cqc Oct 1, 2024
45751ac
anext' allows setting Sources to be skolem
acl-cqc Sep 17, 2024
87270bf
implement isSkolem using TypeOf
acl-cqc Sep 18, 2024
2fcdd48
Common up Checking wrappers via 'wrapper' and 'wrapper2'
acl-cqc Sep 25, 2024
75a5ac0
print hopeset when blocked
acl-cqc Oct 1, 2024
9f1c6ff
Use defineEnd more
acl-cqc Oct 1, 2024
0808dab
Add mkYield, use it
acl-cqc Oct 1, 2024
a83de68
Remove concurrency-blocking -!s in makeBox (27 -> 24 fails)
acl-cqc Oct 1, 2024
98a5671
Remove howStuck, just use Unstuck (30 -> 27 fails)
acl-cqc Oct 1, 2024
db83ba9
typeEqEta shouldWait for ends inside nums as well, assert -> unless
acl-cqc Oct 1, 2024
710c931
Redo invertNatVal
croyzor Oct 3, 2024
3b36023
Refactor typeEqEta
acl-cqc Oct 4, 2024
3e15acc
typeEqEta: fast-path without blocking for both ends the same
acl-cqc Oct 4, 2024
a900ac4
typeEqEta shouldWait for ends inside nums as well, assert -> unless
acl-cqc Oct 1, 2024
3bf4f0b
Refactor typeEqEta
acl-cqc Oct 4, 2024
2c8f26b
typeEqEta: fast-path without blocking for both ends the same
acl-cqc Oct 4, 2024
42ef6d3
Call eval after resumption in simpleCheck
acl-cqc Oct 4, 2024
5b13e9d
Merge remote-tracking branch 'origin/main' into inference-wip/fork
acl-cqc Oct 4, 2024
43bcaf8
Merge remote-tracking branch 'origin/inference-wip/fork' into new/inf…
croyzor Oct 7, 2024
62332cf
Merge remote-tracking branch 'origin/craig/inference-wip/fork-and-nat…
acl-cqc Oct 7, 2024
5517854
SolvePatterns build fixes
acl-cqc Oct 7, 2024
48cd1e2
Merge remote-tracking branch 'origin/main' into inference-wip/fork (c…
acl-cqc Oct 21, 2024
4f8099b
Comment out mapVec
acl-cqc Oct 21, 2024
9203cb6
Fix checking of infer.brat w/note, add more. Compilation fails on Pow ?!
acl-cqc Oct 21, 2024
95dad0f
Revert "TEMP remove failure tests"
acl-cqc Oct 21, 2024
352e9f8
Fix infer.brat, no need to multiply by 2^0
acl-cqc Nov 22, 2024
3c96393
Merge remote-tracking branch 'origin/main' into inference-wip/fork
acl-cqc Nov 22, 2024
7c20289
Fix bad merge, check against HopeSet before vectorise not after
acl-cqc Nov 22, 2024
f783923
Add hole solving but not for nats
croyzor Dec 18, 2024
d981a5b
feat: Add nat hope solving
croyzor Dec 18, 2024
6f9d28a
Merge branch 'main' into just-holes
croyzor Dec 23, 2024
889fb32
Merge remote-tracking branch 'origin/main' into HEAD
acl-cqc Jan 7, 2025
2bc84cf
Drop unnecessary 'derive Ord' for TypeKind
acl-cqc Jan 7, 2025
e32d0b9
Remove repeated export of DIRY in Syntax/Common.hs
acl-cqc Jan 7, 2025
3a60703
review comments
acl-cqc Jan 7, 2025
4965210
another comment
acl-cqc Jan 7, 2025
9b8a997
No need to filter hopes, but clarify with error
acl-cqc Jan 7, 2025
06c454e
Factor out getNumVar, use in typeEq'
acl-cqc Jan 7, 2025
6b05fb6
hlint
acl-cqc Jan 7, 2025
ce5c348
Merge remote-tracking branch 'origin/main' into just-holes
acl-cqc Jan 7, 2025
daf2443
Merge branch 'just-holes' into HEAD
acl-cqc Jan 7, 2025
98c74f8
Don't (re-)export buildNum from SolveHoles.hs
acl-cqc Jan 7, 2025
f5c0a20
and further reduce diff
acl-cqc Jan 7, 2025
8f83c77
Compute 2^constant at compile-time (#74)
acl-cqc Jan 7, 2025
6a94b85
Merge remote-tracking branch 'origin/main' into just-nat-solving
croyzor Apr 1, 2025
90a3ade
[ broken ] troublesome examples of nat solving
Apr 1, 2025
2d9fb1a
Fix demandEven
croyzor Apr 1, 2025
e4010b4
Fix recursive call in `hasfulllen`
croyzor Apr 1, 2025
783107c
[ minor fix ] hasfulllen needs a numeric input
Apr 1, 2025
aa0a509
Fix the other call site that calls `invertNatVal` with a Src
croyzor Apr 1, 2025
03316af
fix some golden/graph tests, mostly internal variable names, plus an …
acl-cqc Apr 1, 2025
9f6f549
Merge remote-tracking branch 'origin/just-nat-solving' into inference…
acl-cqc Apr 1, 2025
d081457
Remove RemoveHope, Define does it automatically
acl-cqc Apr 1, 2025
2c44b1d
Replace Bool with IsSkolem = SkolemConst | Definable
acl-cqc Apr 2, 2025
61dd235
[ progress ] factored out SolveNumbers; started numEq (to be nuked)
Apr 2, 2025
ae05f2e
[ progress ] unifyNum now used in solveHoles as well as solvePatterns…
Apr 2, 2025
b81186a
[ progress ] Fred vs Ginger now a thing.
Apr 2, 2025
09641ea
[ progress ] eatsfullbis.brat now typechecks; long way to go; messy
Apr 3, 2025
5b0c6a8
Skeleton for converting valPats to Valz
croyzor Apr 3, 2025
16ccb96
[wip] Bug hunting
croyzor Apr 4, 2025
4acf90c
[ fix ] makePred now defines the hole to be the succ
Apr 4, 2025
537346b
[ progress ] removed tracing
Apr 7, 2025
36b1a0d
[ progress ] no more Fred and Ginger
Apr 7, 2025
3930d3d
Fix redefinition in make{Half,Pred}
croyzor Apr 7, 2025
1cd750d
Keep track of which hopes are dynamic
croyzor Apr 7, 2025
ae3be34
Better handling of flex-flex case when unifying numbers
croyzor Apr 7, 2025
6724dbd
Accept new golden values, regress vector errors for now
croyzor Apr 7, 2025
a98f429
wip Merge remote-tracking branch 'origin/just-nat-solving' into infer…
croyzor Apr 7, 2025
0802411
Lots of debug printing
croyzor Apr 8, 2025
d95c95f
[ minor progress ] typeEqs forks
Apr 8, 2025
575fa2e
Drop needless call to abstractAll (transitively valMatch)
croyzor Apr 8, 2025
6cbd6f3
Add debug labels to test file
croyzor Apr 8, 2025
4eaf26c
Start dealing in the ownership of unsolved Ends
croyzor Apr 8, 2025
36067bf
Still broken but now compiling
croyzor Apr 9, 2025
1598062
More tracing
croyzor Apr 9, 2025
777b7a6
Allow solving when unifying args with valPat2Val
croyzor Apr 9, 2025
7e77638
[ progress / broken ] new mineToSolve logic not rolled out yet
Apr 9, 2025
d55841a
[ fix ] check in lambda wrapped in $rhs
Apr 9, 2025
4fbaff1
[ fix ] get $checkwire out of $rhs's way; typesEq not unifys!
Apr 9, 2025
6e60114
[ deletion ] unifys is gone
Apr 9, 2025
afbb4c8
[ fix ] more $rhs for check; loc -! solveNumMeta
Apr 9, 2025
ee3de26
map failure: Feature not a bug?
croyzor Apr 11, 2025
f2ee595
Fix bug in solveNumMeta
croyzor Apr 11, 2025
16cedf4
Some yielding in unifyNum
croyzor Apr 11, 2025
6c58256
A smaller test case (delete later)
croyzor Apr 11, 2025
9b404c6
[ fix ] more yielding in unifyNum; no unauthorised solving
Apr 11, 2025
376b2cc
fix bad debug printout
acl-cqc Apr 22, 2025
6bee95a
Remove tracing in Checker.hs
croyzor Apr 28, 2025
b1a312d
Better handling of unifyNum special cases
croyzor Apr 28, 2025
b780f75
Add new dynamic when checking hope
croyzor Apr 28, 2025
4b8302e
Example file that exercises unifyNum + bugfix
croyzor Apr 28, 2025
e806bdb
Comments and fixups from partial review
croyzor Apr 28, 2025
44ba066
New examples
croyzor Apr 28, 2025
d5ca556
Tracing; bug hunting
croyzor Apr 29, 2025
b440a41
[ fix ] zonk after demandEven
Apr 29, 2025
976032a
Accept some golden values
croyzor Apr 29, 2025
b891eb2
Add some metadata to hugr for ad hoc debugging
croyzor Dec 1, 2025
739486e
Merge branch 'main' into inference-wip/ownership
croyzor Dec 8, 2025
8e83732
do not expect vector_solve to compile, it needs Pow
acl-cqc Dec 8, 2025
4d05264
Separate out infer2 failing example
acl-cqc Dec 8, 2025
df76f0c
update graph golden tests
acl-cqc Dec 8, 2025
79ccbc3
brat.cabal: re-enable checks as all passing anyway; fix indenting
acl-cqc Dec 8, 2025
06d030c
spaces to tabs
acl-cqc Dec 8, 2025
042ac58
fix warnings
acl-cqc Dec 8, 2025
2954e62
Update hugr extension
croyzor Dec 8, 2025
98f8186
Turn off traceChecking
croyzor Dec 8, 2025
e592dc8
Pattern matching: Don't discard kinded things with `_` pattern
croyzor Apr 22, 2025
cfdb356
Intercept (problematic)
croyzor Apr 23, 2025
a535dc1
Add dynamic when we see a hope
croyzor Apr 23, 2025
8e0d2cf
Add optional names to Hopes
croyzor Dec 2, 2025
4d1e055
Ditch extra inputs in pattern match; inline undo
croyzor Dec 8, 2025
b30ccd9
Process solutions to find extra implicit srcs
croyzor Dec 8, 2025
c0649b9
Fix BRAT graph: make Hypo instead of Id node for pattern matching
croyzor Dec 8, 2025
8f55383
Feed extra inputs into undo node
croyzor Dec 8, 2025
0d01dc0
Delete commented code
croyzor Dec 8, 2025
f194222
Fix warnings
croyzor Dec 8, 2025
e5d31c4
Dynamics should only be InPorts
croyzor Dec 8, 2025
9e13900
wip: defs and stuff
croyzor Dec 9, 2025
4a7d1bf
Merge remote-tracking branch 'origin/main' into ownership
croyzor Dec 12, 2025
ab31961
Use `find` instead of glob in validation script
croyzor Dec 12, 2025
cece89f
Comment out remaining tests (to follow up on in #92)
croyzor Dec 10, 2025
25e4a02
infer2.brat passes now
croyzor Dec 12, 2025
8e0f2c4
Update golden value (matchOutputs -> rhsInputs)
croyzor Dec 12, 2025
7a61e38
Comment out compilation tests
croyzor Dec 10, 2025
3b476e6
whitespace
acl-cqc Dec 12, 2025
7ad3d63
Delete outdated comment
croyzor Dec 12, 2025
749e7a3
Revert "Comment out compilation tests"
croyzor Dec 12, 2025
3cbe1b7
validate: Fix dodgy find in bash script
croyzor Dec 12, 2025
88cc21f
Stop using assert, it seems unreliable
acl-cqc Dec 12, 2025
df99998
Improve error message in MakeRowTag, and row metadata
acl-cqc Dec 12, 2025
104fac5
xfail test/compilation tests too, for issue #94
acl-cqc Dec 12, 2025
f58f8f8
Revert "Delete commented code"
acl-cqc Dec 13, 2025
8e7496b
Revert "Feed extra inputs into undo node"
acl-cqc Dec 13, 2025
905659d
Revert "Ditch extra inputs in pattern match; inline undo"
acl-cqc Dec 13, 2025
a393b35
Revert "xfail test/compilation tests too, for issue #94"
acl-cqc Dec 13, 2025
0e2174f
Update golden test, xfail compilation infer{,2}, invalid infer_thunks…
acl-cqc Dec 13, 2025
c7196c2
Oops xfail more
acl-cqc Dec 13, 2025
cc81e33
Simplify var-passing in compileConstDfg
acl-cqc Dec 16, 2025
394bd73
Add comments to newly failing compilation tests
croyzor Dec 17, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
323 changes: 230 additions & 93 deletions brat/Brat/Checker.hs

Large diffs are not rendered by default.

451 changes: 345 additions & 106 deletions brat/Brat/Checker/Helpers.hs

Large diffs are not rendered by default.

225 changes: 151 additions & 74 deletions brat/Brat/Checker/Monad.hs

Large diffs are not rendered by default.

105 changes: 45 additions & 60 deletions brat/Brat/Checker/SolveHoles.hs
Original file line number Diff line number Diff line change
@@ -1,23 +1,25 @@
module Brat.Checker.SolveHoles (typeEq) where
module Brat.Checker.SolveHoles (typeEq, typesEq) where

import Brat.Checker.Helpers (buildConst)
import Brat.Checker.Helpers (mineToSolve, solveSem)
import Brat.Checker.Monad
import Brat.Checker.SolveNumbers
import Brat.Checker.Types (kindForMode)
import Brat.Error (ErrorMsg(..))
import Brat.Eval
import Brat.Naming (FreshMonad(..))
import Brat.Syntax.Common
import Brat.Syntax.Simple (SimpleTerm(..))
-- import Brat.Syntax.Simple (SimpleTerm(..))
import Brat.Syntax.Value
import Control.Monad.Freer
import Bwd
import Hasochism
-- import Brat.Syntax.Port (toEnd)

import Control.Monad (when)
import Control.Monad (unless)
import Data.Bifunctor (second)
import Data.Foldable (sequenceA_)
import Data.Functor
import Data.Maybe (mapMaybe)
import qualified Data.Map as M
import qualified Data.Set as S
import Data.Type.Equality (TestEquality(..), (:~:)(..))

-- Demand that two closed values are equal, we're allowed to solve variables in the
Expand All @@ -28,7 +30,20 @@ typeEq :: String -- String representation of the term for error reporting
-> Val Z -- Expected
-> Val Z -- Actual
-> Checking ()
typeEq str = typeEq' str (Zy :* S0 :* S0)
typeEq str k exp act = do
prefix <- whoAmI
trackM ("typeEq: Who am I: " ++ show prefix)
typeEq' str (Zy :* S0 :* S0) k exp act

typesEq :: String -- String representation of the term for error reporting
-> [TypeKind] -- The kinds we're comparing at
-> [Val Z] -- Expected
-> [Val Z] -- Actual
-> Checking ()
typesEq str k exp act = do
prefix <- whoAmI
trackM ("typesEq: Who am I: " ++ show prefix)
typeEqs str (Zy :* S0 :* S0) k exp act


-- Internal version of typeEq with environment for non-closed values
Expand All @@ -38,83 +53,53 @@ typeEq' :: String -- String representation of the term for error reporting
-> Val n -- Expected
-> Val n -- Actual
-> Checking ()
typeEq' str stuff@(_ny :* _ks :* sems) k exp act = do
hopes <- req AskHopes
typeEq' str stuff@(ny :* _ks :* sems) k exp act = do
mine <- mineToSolve
exp <- sem sems exp
act <- sem sems act
typeEqEta str stuff hopes k exp act

isNumVar :: Sem -> Maybe SVar
isNumVar (SNum (NumValue 0 (StrictMonoFun (StrictMono 0 (Linear v))))) = Just v
isNumVar _ = Nothing
qexp <- quote ny exp
qact <- quote ny act
trackM ("typeEq' exp: " ++ show qexp)
trackM ("typeEq' act: " ++ show qact)
typeEqEta str stuff mine k exp act

-- Presumes that the hope set and the two `Sem`s are up to date.
typeEqEta :: String -- String representation of the term for error reporting
-> (Ny :* Stack Z TypeKind :* Stack Z Sem) n
-> Hopes -- A map from the hope set to corresponding FCs
-> (End -> Maybe String) -- Tells us if we can solve a given End
-> TypeKind -- The kind we're comparing at
-> Sem -- Expected
-> Sem -- Actual
-> Checking ()
typeEqEta tm (lvy :* kz :* sems) hopes (TypeFor m ((_, k):ks)) exp act = do
typeEqEta tm (lvy :* kz :* sems) mine (TypeFor m ((_, k):ks)) exp act = do
-- Higher kinded things
let nextSem = semLvl lvy
let xz = B0 :< nextSem
exp <- applySem exp xz
act <- applySem act xz
typeEqEta tm (Sy lvy :* (kz :<< k) :* (sems :<< nextSem)) hopes (TypeFor m ks) exp act
typeEqEta tm (Sy lvy :* (kz :<< k) :* (sems :<< nextSem)) mine (TypeFor m ks) exp act
-- Not higher kinded - check for flex terms
-- (We don't solve under binders for now, so we only consider Zy here)
-- 1. "easy" flex cases
typeEqEta _tm (Zy :* _ks :* _sems) hopes k (SApp (SPar (InEnd e)) B0) act
| M.member e hopes = solveHope k e act
typeEqEta _tm (Zy :* _ks :* _sems) hopes k exp (SApp (SPar (InEnd e)) B0)
| M.member e hopes = solveHope k e exp
typeEqEta _ (Zy :* _ :* _) hopes Nat exp act
| Just (SPar (InEnd e)) <- isNumVar exp, M.member e hopes = solveHope Nat e act
| Just (SPar (InEnd e)) <- isNumVar act, M.member e hopes = solveHope Nat e exp
typeEqEta _tm (Zy :* _ks :* _sems) mine k (SApp (SPar e) B0) act
| Just _ <- mine e = solveSem k e act
typeEqEta _tm (Zy :* _ks :* _sems) mine k exp (SApp (SPar e) B0)
| Just _ <- mine e = solveSem k e exp
typeEqEta _ (Zy :* _ :* _) mine Nat (SNum exp) (SNum act) = unifyNum mine (quoteNum Zy exp) (quoteNum Zy act)
-- 2. harder cases, neither is in the hope set, so we can't define it ourselves
typeEqEta tm stuff@(ny :* _ks :* _sems) hopes k exp act = do
typeEqEta tm stuff@(ny :* _ks :* _sems) _ k exp act = do
exp <- quote ny exp
act <- quote ny act
let ends = mapMaybe getEnd [exp,act]
-- sanity check: we've already dealt with either end being in the hopeset
when (or [M.member ie hopes | InEnd ie <- ends]) $ typeErr "ends were in hopeset"
case ends of
unless (exp == act) $ case flexes act ++ flexes exp of
[] -> typeEqRigid tm stuff k exp act -- easyish, both rigid i.e. already defined
-- variables are trivially the same, even if undefined, but the values may
-- be different! E.g. X =? 1 + X
[_, _] | exp == act -> pure ()
-- TODO: Once we have scheduling, we must wait for one or the other to become more defined, rather than failing
_ -> err (TypeMismatch tm (show exp) (show act))
where
getEnd (VApp (VPar e) _) = Just e
getEnd (VNum n) = getNumVar n
getEnd _ = Nothing

-- This will update the `hopes`, potentially invalidating things that have
-- been eval'd.
-- The Sem is closed, for now.
solveHope :: TypeKind -> InPort -> Sem -> Checking ()
solveHope k hope v = quote Zy v >>= \v -> case doesntOccur (InEnd hope) v of
Right () -> do
defineEnd (InEnd hope) v
dangling <- case (k, v) of
(Nat, VNum _v) -> err $ Unimplemented "Nat hope solving" []
(Nat, _) -> err $ InternalError "Head of Nat wasn't a VNum"
_ -> buildConst Unit TUnit
req (Wire (end dangling, kindType k, hope))
req (RemoveHope hope)
Left msg -> case v of
VApp (VPar (InEnd end)) B0 | hope == end -> pure ()
-- TODO: Not all occurrences are toxic. The end could be in an argument
-- to a hoping variable which isn't used.
-- E.g. h1 = h2 h1 - this is valid if h2 is the identity, or ignores h1.
_ -> err msg
-- tricky: must wait for one or other to become more defined
es -> mkYield "typeEqEta" (S.fromList es) >> typeEq' tm stuff k exp act

typeEqs :: String -> (Ny :* Stack Z TypeKind :* Stack Z Sem) n -> [TypeKind] -> [Val n] -> [Val n] -> Checking ()
typeEqs _ _ [] [] [] = pure ()
typeEqs tm stuff (k:ks) (exp:exps) (act:acts) = typeEqs tm stuff ks exps acts <* typeEq' tm stuff k exp act
typeEqs tm stuff (k:ks) (exp:exps) (act:acts) = do
mkFork "typeEqsTail" $ typeEqs tm stuff ks exps acts
typeEq' tm stuff k exp act
typeEqs _ _ _ _ _ = typeErr "arity mismatch"

typeEqRow :: Modey m
Expand Down Expand Up @@ -145,7 +130,7 @@ typeEqRigid tm (_ :* _ :* semz) Nat exp act = do
act <- sem semz act
if getNum exp == getNum act
then pure ()
else err $ TypeMismatch tm (show exp) (show act)
else err $ TypeMismatch tm ("TYPEEQRIGID " ++ show exp) ("TODO " ++ show act)
typeEqRigid tm stuff@(_ :* kz :* _) (TypeFor m []) (VApp f args) (VApp f' args') | f == f' =
svKind f >>= \case
TypeFor m' ks | m == m' -> typeEqs tm stuff (snd <$> ks) (args <>> []) (args' <>> [])
Expand Down
209 changes: 209 additions & 0 deletions brat/Brat/Checker/SolveNumbers.hs
Original file line number Diff line number Diff line change
@@ -0,0 +1,209 @@
module Brat.Checker.SolveNumbers (unifyNum) where

import Brat.Checker.Monad
import Brat.Checker.Helpers
import Brat.Syntax.Value
import Brat.Syntax.Common
import Brat.Syntax.Port
import Brat.Error
import Brat.Eval
import Brat.Graph (NodeType(..))
import Brat.Naming
import Hasochism
import Control.Monad.Freer

-- import Debug.Trace
import qualified Data.Set as S

trailM :: Applicative f => String -> f ()
trailM = const (pure ())
trail = const id
--trail = trace

-- This is currently lifted from SolvePatterns, which still imports it.
-- It is also used in SolveHoles, where it does the right mathematics
-- but the wrong wiring.

-- Solve a Nat kinded metavariable. Unlike `instantiateMeta`, this function also
-- makes the dynamic wiring for a metavariable. This only needs to happen for
-- numbers because they have nontrivial runtime behaviour.
--
-- We assume that the caller has done the occurs check and rules out trivial equations.
-- The caller also must check we have the right to solve the End
solveNumMeta :: (End -> Maybe String) -> End -> NumVal (VVar Z) -> Checking ()
solveNumMeta _ e nv | trail ("solveNumMeta " ++ show e ++ " " ++ show nv) False = undefined
solveNumMeta mine e nv = case (e, numVars nv) of
-- Compute the thing that the rhs should be based on the src, and instantiate src to that
(ExEnd src, [InEnd _tgt]) -> do
-- Compute the value of the `tgt` variable from the known `src` value by inverting nv
tgtSrc <- invertNatVal nv
instantiateMeta "solveNumExIn" (ExEnd src) (VNum (nVar (VPar (toEnd tgtSrc))))
wire (NamedPort src "", TNat, tgtSrc)

(ExEnd src, _) -> instantiateMeta "solveNumEx_" (ExEnd src) (VNum nv)

-- Both targets, we need to create the thing that they both derive from
(InEnd bigTgt, [InEnd weeTgt]) -> do
(_, [(idTgt, _)], [(idSrc, _)], _) <- anext "numval id" Id (S0, Some (Zy :* S0))
(REx ("n", Nat) R0) (REx ("n", Nat) R0)
defineSrc idSrc (VNum (nVar (VPar (toEnd idTgt))))
let nv' = fmap (const (VPar (toEnd idSrc))) nv -- weeTgt is the only thing to replace
bigSrc <- buildNatVal nv'
nv' <- quoteNum Zy <$> numEval S0 nv'
instantiateMeta "solveNumInIn" (InEnd bigTgt) (VNum nv')
wire (bigSrc, TNat, NamedPort bigTgt "")
unifyNum mine (nVar (VPar (toEnd idSrc))) (nVar (VPar (toEnd weeTgt)))



-- RHS is constant or Src, wire it into tgt
(InEnd tgt, _) -> do
src <- buildNatVal nv
instantiateMeta "solveNumIn_" (InEnd tgt) (VNum nv)
wire (src, TNat, NamedPort tgt "")

unifyNum :: (End -> Maybe String) -> NumVal (VVar Z) -> NumVal (VVar Z) -> Checking ()
unifyNum mine nv0 nv1 = do
trailM $ ("unifyNum In\n " ++ show nv0 ++ "\n " ++ show nv1)
nv0 <- numEval S0 nv0
nv1 <- numEval S0 nv1
unifyNum' mine (quoteNum Zy nv0) (quoteNum Zy nv1)
nv0 <- numEval S0 (quoteNum Zy nv0)
nv1 <- numEval S0 (quoteNum Zy nv1)
trailM $ ("unifyNum Out\n " ++ show (quoteNum Zy nv0) ++ "\n " ++ show (quoteNum Zy nv1))

-- Need to keep track of which way we're solving - which side is known/unknown
-- Things which are dynamically unknown must be Tgts - information flows from Srcs
-- ...But we don't need to do any wiring here, right?
unifyNum' :: (End -> Maybe String) -> NumVal (VVar Z) -> NumVal (VVar Z) -> Checking ()
unifyNum' _ a b | trail ("unifyNum'\n " ++ show a ++ "\n " ++ show b) False = undefined
unifyNum' mine (NumValue lup lgro) (NumValue rup rgro)
| lup <= rup = lhsFun00 lgro (NumValue (rup - lup) rgro)
| otherwise = lhsFun00 rgro (NumValue (lup - rup) lgro)
where
lhsFun00 :: Fun00 (VVar Z) -> NumVal (VVar Z) -> Checking ()
lhsFun00 Constant0 num = demand0 num
-- Both sides are variables
lhsFun00 (StrictMonoFun (StrictMono 0 (Linear v))) (NumValue 0 (StrictMonoFun (StrictMono 0 (Linear v')))) = flexFlex v v'
-- There's just a variable on the right - move it to the left
lhsFun00 sm (NumValue 0 (StrictMonoFun smv@(StrictMono 0 (Linear _)))) = lhsStrictMono smv (NumValue 0 sm)
lhsFun00 (StrictMonoFun sm) num = lhsStrictMono sm num

flexFlex :: VVar Z -> VVar Z -> Checking ()
flexFlex v v' = case compare v v' of
GT -> flexFlex v' v
EQ -> pure ()
LT -> case (v, v') of
(VPar e@(ExEnd p), VPar e'@(ExEnd p'))
| Just _ <- mine e -> defineSrc (NamedPort p "") (VNum (nVar v'))
| Just _ <- mine e' -> defineSrc (NamedPort p' "") (VNum (nVar v))
| otherwise -> typeErr $ "Can't force " ++ show v ++ " to be " ++ show v'
(VPar e@(InEnd p), VPar e'@(ExEnd dangling))
| Just _ <- mine e -> do
req (Wire (dangling, TNat, p))
defineTgt' ("flex-flex In Ex") (NamedPort p "") (VNum (nVar v'))
| Just _ <- mine e' -> do
req (Wire (dangling, TNat, p))
defineSrc' ("flex-flex In Ex") (NamedPort dangling "") (VNum (nVar v))
| otherwise -> mkYield "flexFlex" (S.singleton e) >> unifyNum mine (nVar v) (nVar v')
(VPar e@(InEnd p), VPar e'@(InEnd p'))
| Just _ <- mine e -> defineTgt' "flex-flex In In1" (NamedPort p "") (VNum (nVar v'))
| Just _ <- mine e' -> defineTgt' "flex-flex In In0"(NamedPort p' "") (VNum (nVar v))
| otherwise -> mkYield "flexFlex" (S.fromList [e, e']) >> unifyNum mine (nVar v) (nVar v')

lhsStrictMono :: StrictMono (VVar Z) -> NumVal (VVar Z) -> Checking ()
lhsStrictMono (StrictMono 0 mono) num = lhsMono mono num
lhsStrictMono (StrictMono n mono) num = do
num <- traceChecking "lhsSM demandEven" demandEven num
unifyNum mine (NumValue 0 (StrictMonoFun (StrictMono (n - 1) mono))) num

lhsMono :: Monotone (VVar Z) -> NumVal (VVar Z) -> Checking ()
lhsMono (Linear (VPar e)) num | x <- mine e, trail ("lhsMono\n " ++ show e ++ "\n " ++ show num ++ "\n " ++ show x) False = undefined
-- x = f(x) has 3 solutions, otherwise we should complain!
lhsMono lhs@(Linear (VPar e)) num | [e'] <- numVars num, e == e' = case num of
(NumValue 0 (StrictMonoFun sm)) -> case anyDoubsAnyFulls sm of
(True, _) -> lhsMono lhs (nConstant 0)
(False, True) -> mkYield "lhsMono2Sols" (S.singleton e) >>
unifyNum mine (nVar (VPar e)) num
(False, False) -> pure ()
_ -> err . UnificationError $ "Can't make " ++ show e ++ " = " ++ show num
lhsMono (Linear (VPar e)) num = case mine e of
Just loc -> loc -! solveNumMeta mine e num
_ -> mkYield "lhsMono" (S.singleton e) >>
unifyNum mine (nVar (VPar e)) num
lhsMono (Full sm) (NumValue 0 (StrictMonoFun (StrictMono 0 (Full sm'))))
= lhsFun00 (StrictMonoFun sm) (NumValue 0 (StrictMonoFun sm'))
lhsMono m@(Full _) (NumValue 0 gro) = trail "lhsMono swaps" $ lhsFun00 gro (NumValue 0 (StrictMonoFun (StrictMono 0 m)))
lhsMono (Full sm) (NumValue up gro) = do
smPred <- traceChecking "lhsMono demandSucc" demandSucc (NumValue 0 (StrictMonoFun sm))
_ <- numEval S0 sm
-- trailM $ "succ now " ++ show (quoteNum Zy sm)
unifyNum mine (n2PowTimes 1 (nFull smPred)) (NumValue (up - 1) gro)

anyDoubsAnyFulls :: StrictMono (VVar Z) -> (Bool, Bool)
anyDoubsAnyFulls (StrictMono k (Full rest)) = let (ds,_) = anyDoubsAnyFulls rest in (k > 0 || ds, True)
anyDoubsAnyFulls (StrictMono k (Linear _)) = (k > 0, False)

demand0 :: NumVal (VVar Z) -> Checking ()
demand0 (NumValue 0 Constant0) = pure ()
demand0 n@(NumValue 0 (StrictMonoFun (StrictMono _ mono))) = case mono of
Linear (VPar e) | Just _ <- mine e -> solveNumMeta mine e (nConstant 0)
Full sm -> demand0 (NumValue 0 (StrictMonoFun sm))
_ -> err . UnificationError $ "Couldn't force " ++ show n ++ " to be 0"
demand0 n = err . UnificationError $ "Couldn't force " ++ show n ++ " to be 0"

-- Complain if a number isn't a successor, else return its predecessor
demandSucc :: NumVal (VVar Z) -> Checking (NumVal (VVar Z))
-- 2^k * x
-- = 2^k * (y + 1)
-- = 2^k + 2^k * y
-- Hence, the predecessor is (2^k - 1) + (2^k * y)
demandSucc (NumValue k x) | k > 0 = pure (NumValue (k - 1) x)
demandSucc (NumValue 0 (StrictMonoFun (mono@(StrictMono k (Linear (VPar e))))))
| Just loc <- mine e = do
pred <- loc -! traceChecking "makePred" makePred e
pure (nPlus ((2^k) - 1) (nVar (VPar pred)))

-- 2^k * full(n + 1)
-- = 2^k * (1 + 2 * full(n))
-- = 2^k + 2^(k + 1) * full(n)

| otherwise = do
mkYield "demandSucc" (S.singleton e)
nv <- quoteNum Zy <$> numEval S0 mono
demandSucc nv

-- if it's not "mine" should we wait?
demandSucc (NumValue 0 (StrictMonoFun (StrictMono k (Full nPlus1)))) = do
n <- traceChecking "demandSucc" demandSucc (NumValue 0 (StrictMonoFun nPlus1))
-- foo <- numEval S0 x
-- trailM $ "ds: " ++ show x ++ " -> " ++ show (quoteNum Zy foo)
pure $ nPlus ((2 ^ k) - 1) $ n2PowTimes (k + 1) $ nFull n
demandSucc n = err . UnificationError $ "Couldn't force " ++ show n ++ " to be a successor"

-- Complain if a number isn't even, otherwise return half
demandEven :: NumVal (VVar Z) -> Checking (NumVal (VVar Z))
demandEven (NumValue up gro) = case up `divMod` 2 of
(up, 0) -> nPlus up <$> traceChecking "evenGro" evenGro gro
(up, 1) -> nPlus (up + 1) <$> traceChecking "oddGro" oddGro (NumValue 0 gro)
where
evenGro :: Fun00 (VVar Z) -> Checking (NumVal (VVar Z))
evenGro Constant0 = pure $ nConstant 0
evenGro (StrictMonoFun (StrictMono 0 mono)) = case mono of
Linear (VPar e)
| Just loc <- mine e -> loc -! do
-- trailM $ "Calling makeHalf (" ++ show e ++ ")"
half <- traceChecking "makeHalf" makeHalf e
pure (NumValue 0 (StrictMonoFun (StrictMono 0 (Linear (VPar half)))))
| otherwise -> do
mkYield "evenGro" (S.singleton e)
nv <- quoteNum Zy <$> numEval S0 mono
demandEven nv
Full sm -> nConstant 0 <$ demand0 (NumValue 0 (StrictMonoFun sm))
evenGro (StrictMonoFun (StrictMono n mono)) = pure (NumValue 0 (StrictMonoFun (StrictMono (n - 1) mono)))

-- Check a numval is odd, and return its rounded down half
oddGro :: NumVal (VVar Z) -> Checking (NumVal (VVar Z))
oddGro x = do
pred <- demandSucc x
demandEven pred
Loading
Loading