2022-04-24 17:21:57 +00:00
|
|
|
package gonads
|
|
|
|
|
|
|
|
// Thunk contains a partially computed value. This thunk is also lazy because
|
|
|
|
// it will only run the underlying thunked action _once_ and then return the
|
|
|
|
// result of that action, caching it for further use.
|
|
|
|
//
|
|
|
|
// If this is confusing to you, consider the following JavaScript:
|
|
|
|
//
|
|
|
|
// let add = (x, y) => x + y;
|
|
|
|
// let addCurr = (x) => (y) => x + y;
|
|
|
|
// console.log(add(2, 2)); // 4
|
|
|
|
// console.log(addCurr(2)(2)); // 4
|
|
|
|
// let addTwo = addCurr(2); // (y) => 2 + y;
|
|
|
|
//
|
|
|
|
// In this example, `addTwo` is a thunk that contains a partially applied addCurr
|
|
|
|
// invocation.
|
|
|
|
type Thunk[T any] struct {
|
2022-04-24 23:40:33 +00:00
|
|
|
doer func() T // action being thunked
|
|
|
|
o *Option[T] // cache for complete thunk data
|
2022-04-24 17:21:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Force evaluates a Thunk's action if it needs to, otherwise it returns the
|
|
|
|
// previously evaluated result.
|
2022-04-24 23:33:59 +00:00
|
|
|
func (t Thunk[T]) Force() T {
|
2022-04-24 17:21:57 +00:00
|
|
|
if t.o.IsSome() {
|
|
|
|
return t.o.Yank()
|
|
|
|
}
|
|
|
|
|
2022-04-24 23:33:59 +00:00
|
|
|
t.o.Set(t.doer())
|
2022-04-24 17:21:57 +00:00
|
|
|
return t.o.Yank()
|
|
|
|
}
|
2022-04-24 23:40:33 +00:00
|
|
|
|
|
|
|
func NewThunk[T any](doer func() T) *Thunk[T] {
|
|
|
|
return &Thunk[T]{
|
|
|
|
doer: doer,
|
|
|
|
o: NewOption[T](),
|
|
|
|
}
|
|
|
|
}
|