macrotypes/tapl/notes.txt
Stephen Chang 487c8fedc5 mlish: fix define-type and match
- resolves #1
  - define-type-constructor accepts arbitrary extra "info" that is stored
    with the type
    - get-extra-info extras this info
  - define type stores extra info that is essentially a mu type
    containing all variant info
  - match must manually "unfold" this info, ie iso-recursive
- all tests passing
- mlish tests implements full nqueens example
  - no explicit instantiation of polymorphic functions
  - some polymorphic constructors require annotations when no inference possible
    - a lone nil with no other information
  - lambda params require annotations
  - top lvl fns require full signature
2016-03-02 15:34:51 -05:00

338 lines
13 KiB
Plaintext

2016-02-29
Problem: storing variant info as properties
- when instantiating polymorphic type, need to instantiate properties as well
Alternate Solution: store variant syntactically in (expanded) type
- benefit is instantiation "just works"
- drawbacks:
- recursive types will expand infinitely
- quoting the variant stops infinite expansion but breaks the subst
- ie ids in the quote no longer correspond to the bound id
- can manually stop expansion but then types will no longer always be
fully expanded forms
- tried this a few times previously - can get VERY messy - avoid if possible
- to make this alternate work, can manually fold/unfold recursive types
- cant use \mu from stlc+rec-iso bc each type is more than the mu
so folding/unfolding is a little different
2016-02-19
Implementing algebraic data types
- macro cannot define type-alias and constructor functions that produce
variant values
- not only because adts should be an abstraction (ie not type alias)
- constructor output will have variant type and not the type defined
- macro should basically expand to list implementation in stlc+cons.rkt
- where to store the names of the variants (as stx prop?)
2015-10-09
TODO: variant case should call current-join?
2015-10-09
Can I get rid of current-type-eval?
- would have to put "normalize" call in type=?
- and call normalize in current-promote (before pattern matching)
Thus, it's probably better to keep type-eval
2015-08-16:
TODO:
- generalize binding forms
- add tags to distinguish different binding forms
2015-08-16:
Paper outline
stlc.rkt
Concepts:
- #%app
- lambda
- user input types must be checked
stlc+rec-iso.rkt
Concept(s): binding form, type=? for binding forms
2015-08-13
Requirements for define-type-constructor syntax:
- identifier types, like Int
- basic tuples, like arrow
- arity
- nested tuples, like records
- binding forms, like forall
Problem:
Types must be expanded, to check that they are valid, catch unbound ids, etc.
But should I attach the expanded type to a term, or the original surface stx?
- maybe this is just repeating the same thing I wrote below?
- Related question: fully expand types before calling type=? or typecheck?
Answer: must only compare fully expanded forms, otherwise these will not work
- define-type-alias
Rules:
- all user-written types must be expanded and checked
- check for invalid types, unbound ids
- use expanded types (when available) to create new types
- expand all types before attaching
- assume types are expanded in type=? and typechecks
2015-07-31
Problem: pattern-expander not being recognized
Solution: syntax-parse pattern directives must begin with ~ prefix
2015-07-30:
Problem: How to match against an "expanded" type when I have an unexpanded pat?
- use the 'orig syntax?
- this would probably work but now 'orig is used for more than debugging/msgs
- so dont do this
- also, wont work because you're only matching part of the type
- use pattern expanders!
- a declared literal in define-type-constructor is defined as *both*:
- and macro that applies a temporary id (defined as void)
- a pattern-expander that expands into the expanded form:
((~literal #%plain-app) (~literal tmp-id) . args)
Note to self: when getting weird macro pattern matching errors, always check if you're accidentally using a pattern variable!
2015-07-28
Problem: How to handle mixed types, ie combining expanded and unexpanded types.
Problem: When to eval, ie expand, types into canonical form
Solution:
- use two tags, #%type and #%plain-type, representing surface type syntax and
fully expanded type representation, respectively
- #%type wrapper automatically added by the define-type- macros
- #%plain-type wrapper added by type-eval
- both are macros that expand into their (single) sub-form
- enables elegant mixing of expanded and unexpanded types
- mixed types still need to be eval'ed
- needed to construct other types, eg inferring type of lambda
- enables easy checking of is-type?
- only checks outer wrapper
- rely on each tycon to validate its own arguments
- eval-type only expands if not #%plain-type, ie not already expanded
- this solution thus far does not require any awkward "hacks" in implementations
2015-07-25
Problem: types and terms occur in the same space
What to do about "valid" terms like \x:(void).x or \x:1.x ?
- adding an is-type? predicate that checks shape and other things will only
partially work because things like \x:(void).x will still pass
- define types in a different phase
- wont work because you need terms to do type checking so the terms have to be
in the same phase
- write a separate parser for types
- wont work because still cant tell with a valid binding is a term or type,
eg, \x:(void).x still passes
- unless you hard-code the type names, but then it's not extensible?
- can extend the reader but then you have code duplication?
- wrap types with a tag, like #%type ?
- this might work
- will this have extensibility problems later, ie with records and variants?
2015-07-24
When to canonicalize (ie, eval) types:
- calling eval before matching is too late
- wont catch things like unbound types
- syntax-class evaling is too eager
- sometimes get error when you shouldnt or wrong erro
- eg type (-> 1 2)
- I think the right place is to have \vdash eval
- and rackunit testing forms
2015-06-30
when extending a typed language, use prefix-in for identifiers:
- that are extended, eg #%datum in ext-stlc.rkt
- rename-out the extended implementation of the form
- or when you want to use racket's version, eg #%app in ext-stlc.rkt
- rename-out the prefixed form
- must except-out the prefixed forms, eg stlc:#%app and stlc:#%datum in ext-stlc
2015-06-26
Random thought: Can kinds be "erased"?
- first thought is no, since they appear to be needed for type equality?
- Solution: add them to body of lambda (eg which represents a forall)
2015-06-26
syntax marks problem:
- in the type created by \Lambda, eg \x.(-> x x), the binding x and body x's
were free-id= but not bound-id= because the body x's had extra marks
- this is because (the syntax representing) types are marked going "into" an
expansion, but do not receive the cancelling mark coming *out of* the
expansion since they are attached as a syntax-property
- thus, when this lam goes through another expansion (via \vdash), the binding x
and body x's become neither free-id nor bound-id=?
Solution:
- undo the mark (using syntax-local-introduce) when retrieving the a type
as a syntax property (ie in \vdash)
- need one more syntax-local-introduce in infer/tvs+erase
- i guess the rule is I need as many syntax-local-introduce's as extra
expanding lambdas that I add
2015-06-18
Design Decision:
Types must be fully expanded, if we wish to use expansion to typecheck types
(i.e., kinding).
Problems:
- Type constructors can't be both macro and function
- solution: macro that expands to tmp function
- must provide predicate to check
- Recursive types
- solution: ???
- Displaying error msgs
- need to keep track of surface stx (similar to 'origin prop?)
- solution: ???
- repeated expansion of already expanded types
- solution: ???
- what to do about tuples, where there may be a string in the fn position
- solution: add an extra "type constructor" in front of each pair
- todo: come up with a nicer way to handle "compound" types
- what is the expansion of forall?
2015-06-16
Problem:
use expansion for typechecking of terms: ok
- specifically, ok to go under lambda, since eval happens later
use expansion for typechecking of types: doesnt work now
- doesnt work because types currently are not fully-expandable
- eg a type constructor application (tycon x) is a macro that expands to
(#%app tycon x), where this expression will error if expanded further
since tycon cannot be used as an identifier
- if I define tycon as a regular function, so (tycon x) expands to
(#%app tycon x), then it wont catch non-app uses of tycon
- should be fine? - this is a parsing, not typechecking problem
- but then then parser need to be updated with every new type constructor
- this kind of monolithic architecture is what the paper is trying
to avoid
- alternative: define tycon as a macro where (tycon x) expands to
(#%app tycon_new x)
- drawback: can't use ~literal to match/destructure the tycon
- does this make things like type checking or type=? more difficult?
- will have to go through a separately-defined interface,
like a \tau? predicate
Subproblem: must completely change the representation of types?
- must use fully-expanded forms instead of surface syntax
- in particular, will be using *fully expanded identifiers*
- in this scenario, can I still match with ~literal?
Subproblem: where/when to expand
- types now must all be expanded since that is when kind checking occurs
use expansion for eval of types: not ok
- dont want to go under binders
- expand then eval?
- but then type constructors cant be macros?
Possible Solution
- I think eval must be separate
Subproblem: Do I need a new eval that is different from current-eval?
- conflict:
- current-eval must go under forall to check for unbound ids
- but eval should not go under forall for the case of tyapps
- maybe tyapp should go into type=?, as in tapl?
Subproblem: where to eval
- currently call eval for user type annotations, and in \vdash
Subproblem: Can type=? assume fully expanded (ie, evaled) types?
2015-06-15
New Thesis: The abstractions provided by macro systems are effective at
implementing type systems
2015-06-08
Problem: how to represent \rightarrow kind operator
1) If the kind operator is the same as the function type operator then how do I
attach a kind to a function arrow, since the arrow is still undefined at the
time.
2) If the kind arrow is a different arrow then #%app must be parameterized over
the arrow
2015-05-28
Problem: how to represent \forall types
1) (Racket) functions
- this gets the most linguistic reuse (is this true?)
- but this does not allow equality comparisons
- unless perhaps compare two foralls for equality by applying to the same tvar
- but these type vars would be unbound so it still wouldnt work without
adding a new special case
2) syntax
- easier to compare
- but still need to manually implement alpha equality
- would still require a special case for comparing the bodies, which have
unbound typevars
Problem: begin in lambda body gets spliced
- results in combined syntax properties, eg types
Solution:
- wrap lambda body with #%expression to indicate expression, ie non-splicing,
begin
2015-05-29
Notes: locally-nameless representation of lambdas (and other binding terms)
- syntactically distinguishes bound names vs free vars
- combination of debruijn (nameless) for bound vars and names
- simplifies implementation of capture avoiding substitution
- I already get around by using Racket's identifiers and free-identifier=
to easily implement capture-avoiding subst
- debruijn indices for boundvars avoids having to convert to canonical form
to compare for alpha-equal
- using names for free vars avoids "shifting" of indices when adding or
removing binders, ie free vars dont rely on context
- two main operations:
- open: converts some bound vars to free vars
- eg subst into lambda body
- conversion and subst can be done in one pass?
- close: converts some free vars to bound vars
- eg wrapping a term in a lambda
- similar to subst
- both operations involve traversing the term
- but can do straight-subst (instead of renaming subst) because
shadowing is not possible
- multiple binders are more complicated
- require both depth and offset index
Previous: -----------------
macro system requirements:
- depth-first expansion, i.e., localexpand, and stop-lists
- language form hooks, e.g., #%app, etc
- literal types, e.g. integer syntax class, ie compile time literal type tag
- identifiers and free-identifier=?
- syntax-parse or other pattern matching
Type constructors must be prefix (and not infix) and must be functions
- because in order to support type aliases:
- types must be expanded,
- and having a macro identifier (ie, an alias) in the function position
makes the expander error (constructor is ok bc it is run time identifier)
Type expansion problem: what to do about #%app?
1) use the #%app in scope:
- may do type checking and error bc types dont have types
2) use the racket #%app:
- may work but how to do this without ruining context of other
identifiers (ie types)
Solution: do #1, but
1) stop at the #%app
2) manually drop it and continue expanding rest
Types must be identifiers, but not macros
- cannot be macros if we want to use expansion for type aliases
- because then what does a base type like Int expand to?
- if we define Int as a runtime identifier, then expansion will stop at Int
debugging notes -------------
- "datum" error:
?: literal data is not allowed;
no #%datum syntax transformer is bound in: #f
- likely indicates use of wrong version of some overloaded form
- eg, using stlc:lambda instead of racket's lambda
- vague "bad syntax" error
- means a syntax-parse #:when or #:with matching failed
- ideally would have better err msg at that spot
- #%datum: keyword used as an expression in: #:with
- missing a #:when in front of a printf
- one of type=? arguments is false
- term missing a type
- type missing a kind
- need to transfer syntax properties, eg subst