Express at-most-once evaluation (thunk caching) in types

This commit is contained in:
Stanisław Barzowski 2017-10-02 16:16:26 -04:00 committed by Dave Cunningham
parent 94797696a9
commit 0ec5f40a58
2 changed files with 20 additions and 5 deletions

View File

@ -38,9 +38,19 @@ func (rv *readyValue) bindToObject(sb selfBinding, origBinding bindingFrame, fie
return rv return rv
} }
func (rv *readyValue) aPotentialValue() {}
// potentialValues // potentialValues
// ------------------------------------- // -------------------------------------
// evaluable is something that can be evaluated and the result is always the same
// It may require computation every time evaluation is requested (in contrast with
// potentialValue which guarantees that computation happens at most once).
type evaluable interface {
// fromWhere keeps the information from where the evaluation was requested.
getValue(i *interpreter, fromWhere *TraceElement) (value, error)
}
// thunk holds code and environment in which the code is supposed to be evaluated // thunk holds code and environment in which the code is supposed to be evaluated
type thunk struct { type thunk struct {
env environment env environment
@ -94,10 +104,10 @@ func (th *callThunk) getValue(i *interpreter, trace *TraceElement) (value, error
// TODO(sbarzowski) force use cached/ready everywhere? perhaps an interface tag? // TODO(sbarzowski) force use cached/ready everywhere? perhaps an interface tag?
// TODO(sbarzowski) investigate efficiency of various representations // TODO(sbarzowski) investigate efficiency of various representations
type cachedThunk struct { type cachedThunk struct {
pv potentialValue pv evaluable
} }
func makeCachedThunk(pv potentialValue) *cachedThunk { func makeCachedThunk(pv evaluable) *cachedThunk {
return &cachedThunk{pv} return &cachedThunk{pv}
} }
@ -112,6 +122,8 @@ func (t *cachedThunk) getValue(i *interpreter, trace *TraceElement) (value, erro
return v, nil return v, nil
} }
func (t *cachedThunk) aPotentialValue() {}
// errorThunk can be used when potentialValue is expected, but we already // errorThunk can be used when potentialValue is expected, but we already
// know that something went wrong // know that something went wrong
type errorThunk struct { type errorThunk struct {
@ -126,6 +138,8 @@ func makeErrorThunk(err error) *errorThunk {
return &errorThunk{err} return &errorThunk{err}
} }
func (th *errorThunk) aPotentialValue() {}
// unboundFields // unboundFields
// ------------------------------------- // -------------------------------------

View File

@ -40,14 +40,15 @@ type value interface {
// are not calculated before they are used). It is also a useful abstraction // are not calculated before they are used). It is also a useful abstraction
// in other cases like error handling. // in other cases like error handling.
// //
// It may or may not require computation. // It may or may not require arbitrary computation when getValue is called the
// // first time, but any subsequent calls will immediately return.
// Getting the value a second time may or may not result in additional evaluation.
// //
// TODO(sbarzowski) perhaps call it just "Thunk"? // TODO(sbarzowski) perhaps call it just "Thunk"?
type potentialValue interface { type potentialValue interface {
// fromWhere keeps the information from where the evaluation was requested. // fromWhere keeps the information from where the evaluation was requested.
getValue(i *interpreter, fromWhere *TraceElement) (value, error) getValue(i *interpreter, fromWhere *TraceElement) (value, error)
aPotentialValue()
} }
// A set of variables with associated potentialValues. // A set of variables with associated potentialValues.