///|
pub(all) type Reader[R, A] (R) -> A
///|
pub fn[R, A] Reader::read(reader : Reader[R, A], arg : R) -> A {
reader.inner()(arg)
}
///|
pub fn[R, A] Reader::read_curry(arg : R) -> (Reader[R, A]) -> A {
fn(ra) { ra.read(arg) }
}
///|
pub fn[R, A] Reader::of(a : A) -> Reader[R, A] {
constant(a)
}
///|
pub fn[R, A] Reader::asks(f : (R) -> A) -> Reader[R, A] {
f
}
///|
pub fn[R] Reader::ask() -> Reader[R, R] {
identity
}
///|
pub fn[R, A] Reader::ask_reader(f : (R) -> Reader[R, A]) -> Reader[R, A] {
fn(r) { f(r).read(r) }
}
///|
pub fn[R, A, R2] Reader::locally(
self : Reader[R, A],
f : (R2) -> R
) -> Reader[R2, A] {
fn(r) { self.read(f(r)) }
}
///|
pub fn[R, A, B] Reader::map(self : Reader[R, A], f : (A) -> B) -> Reader[R, B] {
self.inner() |> IReader::map(f)
}
///|
pub fn[R, A, B] Reader::map_trace(
self : Reader[R, A],
f : (A, R) -> B
) -> Reader[R, B] {
fn(r) { self.read(r) |> f(r) }
}
///|
pub fn[R, A, B] Reader::ap(
fab : Reader[R, (A) -> B],
fa : Reader[R, A]
) -> Reader[R, B] {
fn(r) { fab.read(r)(fa.read(r)) }
}
///|
pub fn[R, A, B] Reader::ap_first(
fa : Reader[R, A],
fb : Reader[R, B]
) -> Reader[R, A] {
fa.map(constant).ap(fb)
}
///|
pub fn[R, A, B] Reader::ap_second(
fa : Reader[R, A],
fb : Reader[R, B]
) -> Reader[R, B] {
fa.map(const_identity).ap(fb)
}
///|
pub fn[R, A, B] Reader::ap_tuple(
fa : Reader[R, A],
fb : Reader[R, B]
) -> Reader[R, (A, B)] {
fa.map(curried_tuple_fst).ap(fb)
}
///|
pub fn[R, A, B] Reader::ap_tuple_rev(
fa : Reader[R, A],
fb : Reader[R, B]
) -> Reader[R, (B, A)] {
fa.map(curried_tuple_snd).ap(fb)
}
///|
pub fn[R, A, B] Reader::chain(
self : Reader[R, A],
f : (A) -> Reader[R, B]
) -> Reader[R, B] {
fn(r) { f(self.read(r)).read(r) }
}
///|
pub fn[R, A, B] Reader::chain_first(
self : Reader[R, A],
f : (A) -> Reader[R, B]
) -> Reader[R, A] {
self.chain(fn(a) { f(a).map(constant(a)) })
}
///|
pub fn[R, A] Reader::flatten(self : Reader[R, Reader[R, A]]) -> Reader[R, A] {
self.chain(identity)
}
///|
pub fn[A, B, C] Reader::compose(
ab : Reader[A, B],
bc : Reader[B, C]
) -> Reader[A, C] {
fn(r) { bc.read(ab.read(r)) }
}
///|
pub fn[E, A, B, D] Reader::promap(
fea : Reader[E, A],
f : (D) -> E,
g : (A) -> B
) -> Reader[D, B] {
fn(r) { fea.read(f(r)) |> g }
}
///|
pub fn[R, A, B] Reader::tap(fa : Reader[R, A], f : (A) -> B) -> Reader[R, A] {
fa.map(fn(a) {
a |> f |> ignore
a
})
}
///|
pub fn[A, B] Reader::unwrap(self : Reader[A, B]) -> (A) -> B {
self.inner()
}
///|
pub fn[K : Hash + Eq, V] Reader::memo(f : Reader[K, V]) -> Reader[K, V] {
let map = @hashmap.new()
fn(k : K) -> V {
match map.get(k) {
Some(v) => v
None => {
let v = f.read(k)
map.set(k, v)
v
}
}
}
}
///|
/// Creates a memoized version of a reader that caches the first result and
/// returns it for all subsequent calls, regardless of the input value.
///
/// Parameters:
///
/// * `reader` : A reader function of type `Reader[K, V]` that takes an input of
/// type `K` and produces an output of type `V`.
///
/// Returns a new reader that will compute the value only once on its first call
/// and return the cached value for all subsequent calls.
///
/// Example:
///
/// ```moonbit
/// let counter = StringBuilder::new()
/// let reader = fn(_x : Int) {
/// counter.write_string("computed\n")
/// 42
/// }
/// let memoized = Reader::memo_ignore_arg(reader)
/// inspect(memoized.read(1), content="42")
/// inspect(memoized.read(2), content="42")
/// inspect(counter.to_string(), content="computed\n")
/// ```
pub fn[K, V] Reader::memo_ignore_arg(f : Reader[K, V]) -> Reader[K, V] {
let mut cache = panic_with
cache = fn(k : K) -> V {
let v = f.read(k)
cache = constant(v)
v
}
fn(k) { cache(k) }
}
///|
pub fn[R, A] Reader::from_lazy(lazy_ : Lazy[A]) -> Reader[R, A] {
_a => lazy_.get()
}
///|
pub impl[R, A : Semigroup] Semigroup for Reader[R, A] with op_add(_x, _y) {
r => _x.read(r).op_add(_y.read(r))
}
///|
pub impl[R, A : Default] Default for Reader[R, A] with default() {
Reader(A::default |> lift_arg)
}
///|
fn[R, A, B] Reader::_traverse_non_empty_arrayi(
arr : Array[A],
f : (Int, A) -> Reader[R, B]
) -> Reader[R, Array[B]] {
fn(r) { arr.mapi(fn(i, a) { f(i, a).read(r) }) }
}
///|
pub fn[R, A, B] Reader::_traverse_arrayi(
arr : Array[A],
f : (Int, A) -> Reader[R, B]
) -> Reader[R, Array[B]] {
if arr.length() == 0 {
const_empty_array
} else {
Reader::_traverse_non_empty_arrayi(arr, f)
}
}
///|
pub fn[R, A, B] Reader::traverse_non_empty_arrayi(
f : (Int, A) -> Reader[R, B]
) -> (Array[A]) -> Reader[R, Array[B]] {
fn(arr) { Reader::_traverse_non_empty_arrayi(arr, f) }
}
///|
pub fn[R, A, B] Reader::traverse_arrayi(
f : (Int, A) -> Reader[R, B]
) -> (Array[A]) -> Reader[R, Array[B]] {
fn(arr) { Reader::_traverse_arrayi(arr, f) }
}
///|
pub fn[R, A, B] Reader::traverse_array(
f : (A) -> Reader[R, B]
) -> (Array[A]) -> Reader[R, Array[B]] {
Reader::traverse_arrayi(fn(_i, a) { f(a) })
}
///|
pub fn[R, A] Reader::sequence_array(
arr : Array[Reader[R, A]]
) -> Reader[R, Array[A]] {
Reader::_traverse_arrayi(arr, fn(_i, a) { a })
}
///|
pub fn[R, A] Reader::sequence_fixed_array(
arr : FixedArray[Reader[R, A]]
) -> Reader[R, FixedArray[A]] {
let (self, target) = (Indexable::fixed_array(), Indexable::fixed_array())
fn(r) {
self.sequence_transform(arr, curried_first(Reader::read, r), target~)
}
}
///|
pub fn[R, A] Reader::sequence_many(
arr : Many[Reader[R, A]]
) -> Reader[R, Many[A]] {
let (self, target) = (Indexable::many(), Indexable::many())
fn(r) {
self.sequence_transform(arr, curried_first(Reader::read, r), target~)
}
}
///|
pub fn[R, K : Hash + Eq, A] Reader::sequence_map(
map : Map[K, Reader[R, A]]
) -> Reader[R, Map[K, A]] {
fn(r) { map |> MapFunctor::map(Reader::read_curry(r)) }
}
///|
pub fn[R, K : Hash + Eq, A] Reader::bind_to_map(
self : Reader[R, A],
key : K
) -> Reader[R, Map[K, A]] {
self.map(fn(a) {
let map = Map::new()
map..set(key, a)
map
})
}
///|
pub fn[R, K : Hash + Eq, A] Reader::bind_map(
self : Reader[R, Map[K, A]],
key : K,
fa : Reader[R, A]
) -> Reader[R, Map[K, A]] {
self.chain(fn(map) {
fa.map(fn(a) { map.iter() |> iter_append((key, a)) |> Map::from_iter })
})
}
///|
pub fn[R, A : ToJson] Reader::bind_to_json(
self : Reader[R, A],
key : String
) -> Reader[R, Json] {
self.map(fn(a) {
let json : Json = a.to_json()
let map = Map::new()
map.set(key, json)
Json::object(map)
})
}
///|
pub fn[R, A : ToJson] Reader::bind_json(
self : Reader[R, Json],
key : String,
fa : Reader[R, A]
) -> Reader[R, Json] {
self.chain(fn(a) {
match a {
Object(map) =>
fa.map(fn(a) {
let json : Json = a.to_json()
Json::object(map.iter() |> iter_append((key, json)) |> Map::from_iter)
})
_ => if DEBUGGER { abort("json is not a object") } else { panic() }
}
})
}
///|
test {
let arg = [
..[1, 2, 3, 4].map(Reader::of),
Reader::ask(),
Reader::ask().map(a => a + 1),
]
inspect(Reader::sequence_array(arg).read(5), content="[1, 2, 3, 4, 5, 6]")
}
///|
#external
pub type ReaderT
// pub fn ReaderT::map[R, A, B](reader: Reader[R, A], ) -> (A, B) {
// }