/*---------------------------------------------------------------------------
  Copyright 2023-2024, Microsoft Research, Daan Leijen.

  This is free software; you can redistribute it and/or modify it under the
  terms of the Apache License, Version 2.0. A copy of the License can be
  found in the LICENSE file at the root of this distribution.
---------------------------------------------------------------------------*/

// Delayed computations.
module std/core/delayedstd/core/delayed

import std/core/typesstd/core/types
import std/core/hndstd/core/hnd
import std/core/unsafestd/core/unsafe

// ----------------------------------------------------------------------------
// Delayed values
// ----------------------------------------------------------------------------

reference type computationstd/core/delayed/computation: (E, V) -> V<ee: E, aa: V>
  con XComputationstd/core/delayed/XComputation: forall<e,a> (action : () -> e a) -> computation<e,a>( action : () -> ee: E aa: V )
  con XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>( value : aa: V )
  con XBlockingstd/core/delayed/XBlocking: forall<e,a> computation<e,a>

// Delayed (or _lazy_) values are computed (with effect `:e`) only the first time
// `force` is called and cached afterwards.
abstract value type delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
  con XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,computation<e,a>>) -> delayed<e,a>( drefstd/core/delayed/delayed/dref: forall<e,a> (delayed : delayed<e,a>) -> ref<global,computation<e,a>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,computationstd/core/delayed/computation: (E, V) -> V<ee: E,aa: V>> )

// Create a new `:delayed` value.
pub fun delaystd/core/delayed/delay: forall<a,e> (action : () -> e a) -> delayed<e,a>( actionaction: () -> $264 $263 : () -> ee: E aa: V )result: -> total delayed<319,318> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_283> delayed<$264,$263>) -> delayed<$264,$263>
    val rr: ref<global,computation<$264,$263>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,computationstd/core/delayed/computation: (E, V) -> V<__w-l33-c36: E,__w-l33-c38: V>> = refstd/core/types/ref: (value : computation<$264,$263>) -> <alloc<global>|_283> ref<global,computation<$264,$263>>(XComputationstd/core/delayed/XComputation: forall<e,a> (action : () -> e a) -> computation<e,a>(actionaction: () -> $264 $263))
    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,computation<e,a>>) -> delayed<e,a>(rr: ref<global,computation<$264,$263>>)

// Create a new `:delayed` value.
pub fun memostd/core/delayed/memo: forall<a,e> (value : a) -> delayed<e,a>( valuevalue: $327 : aa: V )result: -> total delayed<383,382> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E, aa: V>
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_347> delayed<$328,$327>) -> delayed<$328,$327>
    val rr: ref<global,computation<$328,$327>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,computationstd/core/delayed/computation: (E, V) -> V<__w-l39-c36: E,__w-l39-c38: V>> = refstd/core/types/ref: (value : computation<$328,$327>) -> <alloc<global>|_347> ref<global,computation<$328,$327>>(XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(valuevalue: $327))
    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,computation<e,a>>) -> delayed<e,a>(rr: ref<global,computation<$328,$327>>)

pub fun force/gostd/core/delayed/force/go: forall<a,e> (delayed : delayed<e,a>) -> <st<global>,div|e> a( delayeddelayed: delayed<$392,$391> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> <div,read<global>,write<global>,alloc<global>|532> 531 : <divstd/core/types/div: X,readstd/core/types/read: H -> X<globalstd/core/types/global: H>,writestd/core/types/write: H -> X<globalstd/core/types/global: H>,allocstd/core/types/alloc: H -> X<globalstd/core/types/global: H>|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V
  val rr: ref<global,computation<$392,$391>> = delayeddelayed: delayed<$392,$391>.drefstd/core/delayed/delayed/dref: (delayed : delayed<$392,$391>) -> <alloc<global>,div,read<global>,write<global>|$392> ref<global,computation<$392,$391>>
  match !std/core/types/ref/(!): (ref : ref<global,computation<$392,$391>>, @implicit/hdiv : hdiv<global,computation<$392,$391>,<alloc<global>,div,write<global>|$392>>) -> <read<global>,alloc<global>,div,write<global>|$392> computation<$392,$391>
?hdiv=iev@412
rr: ref<global,computation<$392,$391>> XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(xx: $391) -> xx: $391 XBlockingstd/core/delayed/XBlocking: forall<e,a> computation<e,a> -> delayeddelayed: delayed<$392,$391>.gostd/core/delayed/force/go: (delayed : delayed<$392,$391>) -> <div,read<global>,write<global>,alloc<global>|$392> $391() XComputationstd/core/delayed/XComputation: forall<e,a> (action : () -> e a) -> computation<e,a>(actionaction: () -> $392 $391) -> rr: ref<global,computation<$392,$391>> :=std/core/types/set: (ref : ref<global,computation<$392,$391>>, assigned : computation<$392,$391>) -> <write<global>,alloc<global>,div,read<global>|$392> () XBlockingstd/core/delayed/XBlocking: forall<e,a> computation<e,a> // ensure that action can be unique val xx: $391 = mask-ststd/core/types/mask-st: (action : () -> <div|$392> $391) -> <alloc<global>,div,read<global>,write<global>|$392> (() -> <st<global>,div|$392> $391){ mask<divstd/core/types/div: X>(actionaction: () -> $392 $391) }() rr: ref<global,computation<$392,$391>> :=std/core/types/set: (ref : ref<global,computation<$392,$391>>, assigned : computation<$392,$391>) -> <write<global>,alloc<_479>,div,read<_479>|$392> () XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(xx: $391)
xx: $391 fun unsafe-no-state-divstd/core/delayed/unsafe-no-state-div: forall<a,e> (f : () -> <st<global>,div|e> a) -> e a(ff: () -> <st<global>,div|$584> $583 : () -> <ststd/core/types/st: H -> E<globalstd/core/types/global: H>,divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V)result: -> 607 606: ee: E aa: V unsafe-no-state-div-caststd/core/delayed/unsafe-no-state-div-cast: (f : () -> <st<global>,div|$584> $583) -> $584 (() -> $584 $583)(ff: () -> <st<global>,div|$584> $583)() extern unsafe-no-state-div-caststd/core/delayed/unsafe-no-state-div-cast: forall<a,e> (f : () -> <st<global>,div|e> a) -> (() -> e a)(ff: () -> <st<global>,div|$552> $551 : () -> <ststd/core/types/st: H -> E<globalstd/core/types/global: H>,divstd/core/types/div: X|std/core/types/effect-extend: (X, E) -> Eee: E> aa: V): ((std/core/types/total: E) -> ee: E aa: V) inline "#1" // Force a delayed value; the value is computed only on the first // call to `force` and cached afterwards. pub fun forcestd/core/delayed/force: forall<a,e> (delayed : delayed<e,a>) -> e a( delayeddelayed: delayed<$615,$614> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> 644 643 : ee: E aa: V unsafe-no-state-divstd/core/delayed/unsafe-no-state-div: (f : () -> <st<global>,div|$615> $614) -> $615 $614 force/gostd/core/delayed/force/go: (delayed : delayed<$615,$614>) -> <st<global>,div|$615> $614(delayeddelayed: delayed<$615,$614>) // Given a total function to calculate a value `:a`, return // a total function that only calculates the value once and then // returns the cached result. pub fun oncestd/core/delayed/once: forall<a> (calc : () -> a) -> (() -> a)( calccalc: () -> $651 : () -> astd/core/types/total: E )result: -> total () -> 756 : ((std/core/types/total: E) -> astd/core/types/total: E) unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<_670>|_671> (() -> $651)) -> (() -> $651) val rr: ref<_670,maybe<$651>> = refstd/core/types/ref: (value : maybe<$651>) -> <alloc<_670>|_671> ref<_670,maybe<$651>>(Nothingstd/core/types/Nothing: forall<a> maybe<a>) returnreturn: () -> $651 fnfn: () -> $651() unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<_670>,write<_670>,div|_748> $651) -> $651 match !std/core/types/ref/(!): (ref : ref<_670,maybe<$651>>, @implicit/hdiv : hdiv<_670,maybe<$651>,<write<_670>,div|_748>>) -> <read<_670>,write<_670>,div|_748> maybe<$651>
?hdiv=iev@694
rr: ref<_670,maybe<$651>> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $651) -> xx: $651 Nothingstd/core/types/Nothing: forall<a> maybe<a> -> val xx: $651 = calccalc: () -> <write<_670>,read<_670>,div|_748> $651() rr: ref<_670,maybe<$651>> :=std/core/types/set: (ref : ref<_670,maybe<$651>>, assigned : maybe<$651>) -> <write<_670>,read<_670>,div|_748> () Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $651)
xx: $651