/*---------------------------------------------------------------------------
  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: () -> $235 $234 : () -> ee: E aa: V )result: -> total delayed<290,289> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_254> delayed<$235,$234>) -> delayed<$235,$234>
    val rr: ref<global,computation<$235,$234>> : 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<$235,$234>) -> <alloc<global>|_254> ref<global,computation<$235,$234>>(XComputationstd/core/delayed/XComputation: forall<e,a> (action : () -> e a) -> computation<e,a>(actionaction: () -> $235 $234))
    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,computation<e,a>>) -> delayed<e,a>(rr: ref<global,computation<$235,$234>>)

// Create a new `:delayed` value.
pub fun memostd/core/delayed/memo: forall<a,e> (value : a) -> delayed<e,a>( valuevalue: $298 : aa: V )result: -> total delayed<354,353> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E, aa: V>
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_318> delayed<$299,$298>) -> delayed<$299,$298>
    val rr: ref<global,computation<$299,$298>> : 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<$299,$298>) -> <alloc<global>|_318> ref<global,computation<$299,$298>>(XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(valuevalue: $298))
    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,computation<e,a>>) -> delayed<e,a>(rr: ref<global,computation<$299,$298>>)

pub fun force/gostd/core/delayed/force/go: forall<a,e> (delayed : delayed<e,a>) -> <st<global>,div|e> a( delayeddelayed: delayed<$363,$362> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> <div,read<global>,write<global>,alloc<global>|503> 502 : <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<$363,$362>> = delayeddelayed: delayed<$363,$362>.drefstd/core/delayed/delayed/dref: (delayed : delayed<$363,$362>) -> <alloc<global>,div,read<global>,write<global>|$363> ref<global,computation<$363,$362>>
  match !std/core/types/ref/(!): (ref : ref<global,computation<$363,$362>>, @implicit/hdiv : hdiv<global,computation<$363,$362>,<alloc<global>,div,write<global>|$363>>) -> <read<global>,alloc<global>,div,write<global>|$363> computation<$363,$362>
?hdiv=iev@383
rr: ref<global,computation<$363,$362>> XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(xx: $362) -> xx: $362 XBlockingstd/core/delayed/XBlocking: forall<e,a> computation<e,a> -> delayeddelayed: delayed<$363,$362>.gostd/core/delayed/force/go: (delayed : delayed<$363,$362>) -> <div,read<global>,write<global>,alloc<global>|$363> $362() XComputationstd/core/delayed/XComputation: forall<e,a> (action : () -> e a) -> computation<e,a>(actionaction: () -> $363 $362) -> rr: ref<global,computation<$363,$362>> :=std/core/types/set: (ref : ref<global,computation<$363,$362>>, assigned : computation<$363,$362>) -> <write<global>,alloc<global>,div,read<global>|$363> () XBlockingstd/core/delayed/XBlocking: forall<e,a> computation<e,a> // ensure that action can be unique val xx: $362 = mask-ststd/core/types/mask-st: (action : () -> <div|$363> $362) -> <alloc<global>,div,read<global>,write<global>|$363> (() -> <st<global>,div|$363> $362){ mask<divstd/core/types/div: X>(actionaction: () -> $363 $362) }() rr: ref<global,computation<$363,$362>> :=std/core/types/set: (ref : ref<global,computation<$363,$362>>, assigned : computation<$363,$362>) -> <write<global>,alloc<_450>,div,read<_450>|$363> () XDonestd/core/delayed/XDone: forall<e,a> (value : a) -> computation<e,a>(xx: $362)
xx: $362 // 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<$523,$522> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> 554 553 : ee: E aa: V unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>,div,read<global>,write<global>|$523> $522) -> $523 $522(fnfn: () -> <alloc<global>,div,read<global>,write<global>|$523> $522() -> force/gostd/core/delayed/force/go: (delayed : delayed<$523,$522>) -> <st<global>,div|$523> $522(delayeddelayed: delayed<$523,$522>)) // 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: () -> $561 : () -> astd/core/types/total: E )result: -> total () -> 666 : ((std/core/types/total: E) -> astd/core/types/total: E) unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<_580>|_581> (() -> $561)) -> (() -> $561) val rr: ref<_580,maybe<$561>> = refstd/core/types/ref: (value : maybe<$561>) -> <alloc<_580>|_581> ref<_580,maybe<$561>>(Nothingstd/core/types/Nothing: forall<a> maybe<a>) returnreturn: () -> $561 fnfn: () -> $561() unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<_580>,write<_580>,div|_658> $561) -> $561 match !std/core/types/ref/(!): (ref : ref<_580,maybe<$561>>, @implicit/hdiv : hdiv<_580,maybe<$561>,<write<_580>,div|_658>>) -> <read<_580>,write<_580>,div|_658> maybe<$561>
?hdiv=iev@604
rr: ref<_580,maybe<$561>> Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $561) -> xx: $561 Nothingstd/core/types/Nothing: forall<a> maybe<a> -> val xx: $561 = calccalc: () -> <write<_580>,read<_580>,div|_658> $561() rr: ref<_580,maybe<$561>> :=std/core/types/set: (ref : ref<_580,maybe<$561>>, assigned : maybe<$561>) -> <write<_580>,read<_580>,div|_658> () Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $561)
xx: $561