add thunk type
Signed-off-by: Xe Iaso <me@christine.website>
This commit is contained in:
parent
9804c6b7b0
commit
550ad6721e
18
option.go
18
option.go
|
@ -21,13 +21,23 @@ func (o Option[T]) IsNone() bool {
|
||||||
return !o.IsSome()
|
return !o.IsSome()
|
||||||
}
|
}
|
||||||
|
|
||||||
// Take a value out of the option if it exists.
|
// Yank will pull a value out of an option, panicking if it doesn't exist.
|
||||||
func (o Option[T]) Take() (*T, error) {
|
func (o Option[T]) Yank() T {
|
||||||
if o.IsNone() {
|
if o.IsNone() {
|
||||||
return nil, ErrOptionIsNone
|
panic("gonads: Yank on None Option")
|
||||||
}
|
}
|
||||||
|
|
||||||
return o.val, nil
|
return *o.val
|
||||||
|
}
|
||||||
|
|
||||||
|
// Take a value out of the option if it exists.
|
||||||
|
func (o Option[T]) Take() (T, error) {
|
||||||
|
if o.IsNone() {
|
||||||
|
var zero T
|
||||||
|
return zero, ErrOptionIsNone
|
||||||
|
}
|
||||||
|
|
||||||
|
return *o.val, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Set the value of the option to a given value.
|
// Set the value of the option to a given value.
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
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 {
|
||||||
|
doer func(T) T // action being thunked
|
||||||
|
o Option[T] // cache for complete thunk data
|
||||||
|
}
|
||||||
|
|
||||||
|
// Force evaluates a Thunk's action if it needs to, otherwise it returns the
|
||||||
|
// previously evaluated result.
|
||||||
|
func (t Thunk[T]) Force(inp T) T {
|
||||||
|
if t.o.IsSome() {
|
||||||
|
return t.o.Yank()
|
||||||
|
}
|
||||||
|
|
||||||
|
t.o.Set(t.doer(inp))
|
||||||
|
return t.o.Yank()
|
||||||
|
}
|
|
@ -0,0 +1,32 @@
|
||||||
|
package gonads
|
||||||
|
|
||||||
|
import (
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func Fib(n int) int {
|
||||||
|
if n <= 1 {
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
return Fib(n-1) + Fib(n-2)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestRecurFib(t *testing.T) {
|
||||||
|
t.Log(Fib(40))
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestThunkFib(t *testing.T) {
|
||||||
|
cache := make([]Thunk[int], 41)
|
||||||
|
cache[0].o.Set(0)
|
||||||
|
cache[1].o.Set(1)
|
||||||
|
|
||||||
|
fib := func(n int) int {
|
||||||
|
return cache[n-1].Force(n-1) + cache[n-2].Force(n-2)
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range cache {
|
||||||
|
cache[i].doer = fib
|
||||||
|
}
|
||||||
|
|
||||||
|
t.Log(cache[40].Force(40))
|
||||||
|
}
|
Loading…
Reference in New Issue