/*---------------------------------------------------------------------------
  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
// ----------------------------------------------------------------------------

// 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,either<() -> e a,a>>) -> delayed<e,a>( drefstd/core/delayed/delayed/dref: forall<e,a> (delayed : delayed<e,a>) -> ref<global,either<() -> e a,a>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,eitherstd/core/types/either: (V, V) -> V<() -> ee: E aa: V,aa: V>> )

// Create a new `:delayed` value.
pub fun delaystd/core/delayed/delay: forall<a,e> (action : () -> e a) -> delayed<e,a>( actionaction: () -> $125 $124 : () -> ee: E aa: V )result: -> total delayed<176,175> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V>
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>|_143> delayed<$125,$124>) -> delayed<$125,$124>
    val rr: ref<global,either<() -> $125 $124,$124>> : refstd/core/types/ref: (H, V) -> V<globalstd/core/types/global: H,eitherstd/core/types/either: (V, V) -> V<__w-l28-c31: V,__w-l28-c33: V>> = refstd/core/types/ref: (value : either<() -> $125 $124,$124>) -> <alloc<global>|_143> ref<global,either<() -> $125 $124,$124>>(Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(actionaction: () -> $125 $124))
    XDelaystd/core/delayed/XDelay: forall<e,a> (dref : ref<global,either<() -> e a,a>>) -> delayed<e,a>(rr: ref<global,either<() -> $125 $124,$124>>)

// 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<$185,$184> : delayedstd/core/delayed/delayed: (E, V) -> V<ee: E,aa: V> )result: -> 293 292 : ee: E aa: V
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<global>,div,read<global>,write<global>|$185> $184) -> $185 $184
    val rr: ref<global,either<() -> $185 $184,$184>> = delayeddelayed: delayed<$185,$184>.drefstd/core/delayed/delayed/dref: (delayed : delayed<$185,$184>) -> <alloc<global>,div,read<global>,write<global>|$185> ref<global,either<() -> $185 $184,$184>>
    match !std/core/types/ref/(!): (ref : ref<global,either<() -> $185 $184,$184>>) -> <read<global>,div,alloc<global>,write<global>|$185> either<() -> $185 $184,$184>rr: ref<global,either<() -> $185 $184,$184>>
      Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $184) -> xx: $184
      Leftstd/core/types/Left: forall<a,b> (left : a) -> either<a,b>(actionaction: () -> $185 $184) ->
        val xx: $184 = mask-ststd/core/types/mask-st: (() -> <div|$185> $184) -> <alloc<global>,div,read<global>,write<global>|$185> (() -> <st<global>,div|$185> $184){ mask<divstd/core/types/div: X>(actionaction: () -> $185 $184) }()
        rr: ref<global,either<() -> $185 $184,$184>> :=std/core/types/set: (ref : ref<global,either<() -> $185 $184,$184>>, assigned : either<() -> $185 $184,$184>) -> <write<global>,alloc<_245>,div,read<_245>|$185> () Rightstd/core/types/Right: forall<a,b> (right : b) -> either<a,b>(xx: $184)
        xx: $184

// 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: () -> $300 : () -> astd/core/types/total: E )result: -> total () -> 396 : ((std/core/types/total: E) -> astd/core/types/total: E)
  unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <alloc<_318>|_319> (() -> $300)) -> (() -> $300)
    val rr: ref<_318,maybe<$300>> = refstd/core/types/ref: (value : maybe<$300>) -> <alloc<_318>|_319> ref<_318,maybe<$300>>(Nothingstd/core/types/Nothing: forall<a> maybe<a>)
    returnreturn: () -> $300 fnfn: () -> $300()
      unsafe-totalstd/core/unsafe/unsafe-total: (action : () -> <read<_318>,write<_318>,div|_388> $300) -> $300
        match !std/core/types/ref/(!): (ref : ref<_318,maybe<$300>>) -> <read<_318>,write<_318>,div|_388> maybe<$300>rr: ref<_318,maybe<$300>>
          Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $300) -> xx: $300
          Nothingstd/core/types/Nothing: forall<a> maybe<a> ->
            val xx: $300 = calccalc: () -> <write<_318>,read<_318>,div|_388> $300()
            rr: ref<_318,maybe<$300>> :=std/core/types/set: (ref : ref<_318,maybe<$300>>, assigned : maybe<$300>) -> <write<_318>,read<_318>,div|_388> () Juststd/core/types/Just: forall<a> (value : a) -> maybe<a>(xx: $300)
            xx: $300