change loop function so you can write ().loop(() -> do_smth)

This commit is contained in:
Mark 2023-11-08 15:11:28 +01:00
parent cab81059f3
commit 39fca08541
5 changed files with 37 additions and 23 deletions

View File

@ -1,10 +1,10 @@
total := 0.0
{() -> {
().loop(() -> {
("Total: ", total, ". Type a number to change.").concat.println
().read_line.trim.parse_float.try((
n -> &total = (total, n).sum,
// not a number, so return a 1-tuple to break from the loop
() -> (())
))
}}.loop
})
"Goodbye.".println

View File

@ -5,7 +5,7 @@
current := 0.0
{() -> {
().loop(() -> {
("[ ", current, " ]").concat.println
input := ().read_line.trim
num := (input, 1).substring.trim.parse_float.try((
@ -24,4 +24,4 @@ current := 0.0
} else if input.eq("exit") {
(())
}
}}.loop
})

View File

@ -1,5 +1,5 @@
gcd := vals -> {
() -> {
().loop(() -> {
(a, b) := vals
if a.eq(b)
(a)
@ -7,8 +7,8 @@ gcd := vals -> {
&vals = (a, b.subtract(a))
else
&vals = (a.subtract(b), b)
}
}.loop
})
}
get_num := () -> {
line := ().read_line.trim

View File

@ -17,7 +17,7 @@ split_once := (s, delim) -> {
split_ := (s, delim, require_nonempty) -> {
out := (s).as_list
&out.pop
{
().loop(
() -> s.split_once(delim).try((
(s1, s2) -> {
&s = s2
@ -30,7 +30,7 @@ split_ := (s, delim, require_nonempty) -> {
(())
}
))
}.loop
)
out
}
@ -62,9 +62,11 @@ read_matrix_line := width -> {
if w.eq(0) {
width = line.len
} else {
{() -> if line.len.subtract(w).signum.eq(-1) {
&line.push(0.0)
} else (())}.loop
().loop(() ->
if line.len.subtract(w).signum.eq(-1) {
&line.push(0.0)
} else (())
)
}
(line)
}
@ -87,10 +89,12 @@ matrix_get := (matrix, (line, col)) -> {
leftpad := (str, l) -> {
str := (str).concat
d := l.subtract(str.len)
{() -> if d.signum.eq(1) {
&str = (" ", str).concat
&d = d.subtract(1)
} else {(())}}.loop
().loop(() ->
if d.signum.eq(1) {
&str = (" ", str).concat
&d = d.subtract(1)
} else (())
)
str
}

View File

@ -13,7 +13,7 @@ use super::Config;
impl Config {
/// `deref: fn` clones the value from a reference
/// `eq: fn` returns true if all the values are equal, otherwise false.
/// `loop: fn` runs a function until it returns (T) instead of (), then returns T.
/// `loop: fn` runs a function until it returns (T) instead of (), then returns T. Also works with ((), f) instead of f for ().loop(() -> { ... }) syntax, which may be more readable
/// `try: fn` runs the first valid function with the argument. usage: (arg, (f1, f2, f3)).try
/// NOTE: try's return type may miss some types that can actually happen when using it on tuples, so... don't do ((a, b), (f1, any -> ())).try unless f1 also returns ()
/// `len: fn` gets the length of strings or tuples
@ -180,7 +180,11 @@ impl Config {
info_check: Arc::new(Mutex::new(CheckInfo::neverused())),
out: Arc::new(|a, _i| {
let mut o = Type::empty();
for t in &a.types {
for t in a.types.iter().flat_map(|v| if let Some(t) = v.as_any().downcast_ref::<data::tuple::TupleT>() {
if let Some(t) = t.0.get(1) {
t.types.iter().collect::<Vec<_>>()
} else { [v].into_iter().collect() }
} else { [v].into_iter().collect() }) {
if let Some(t) = t.as_any().downcast_ref::<data::function::FunctionT>() {
for t in (t.0)(&Type::empty_tuple())?.types {
if let Some(t) = t.as_any().downcast_ref::<data::tuple::TupleT>() {
@ -200,15 +204,21 @@ impl Config {
Ok(o)
}),
run: Arc::new(|a, _i| {
if let Some(r) = a.get().as_any().downcast_ref::<data::function::Function>() {
let a = a.get();
let delay_drop;
let function = if let Some(function) = a.as_any().downcast_ref::<data::function::Function>() {
function
} else if let Some(r) = a.as_any().downcast_ref::<data::tuple::Tuple>() {
delay_drop = r.0[1].get();
delay_drop.as_any().downcast_ref::<data::function::Function>().unwrap()
} else {
unreachable!("called loop on non-function")
};
loop {
if let Some(r) = r.run(Data::empty_tuple()).one_tuple_content() {
if let Some(r) = function.run(Data::empty_tuple()).one_tuple_content() {
break r;
}
}
} else {
unreachable!("called loop on non-function")
}
}),
}),
)