#maintaining internal state with list.fold or list.scan
1 messages · Page 1 of 1 (latest)
for example, this rather contrived example
import gleam/list
import gleam/io
import gleam/pair
pub fn main() {
list.range(1, 100)
|> list.shuffle
|> list.scan(#(0, False), fn(acc, num) {
let #(prev, _) = acc
case prev - num > 0 {
True -> #(num, True)
False -> #(num, False)
}
})
|> list.map(pair.second)
|> io.debug
}
(along a similar line, something that's possible in python, i.e.
for (a, b) in [(1, 2), (3, 4)]:
# do stuff
being able to do that in functions would also be helpful?
fn(#(prev, _), num) {}
since that at least removes the need for the destructuring
This is brought up from time to time, here is one discussion: https://github.com/gleam-lang/gleam/discussions/1451
My coworker is doing AoC in Gleam this year and also mentioned they would like to see this allowed
My main worry is that it would be confusing (e.g. to beginners) why only tuple pattern is allowed in a function head. Possibly this would also add a little bit of complexity to the compiler codebase? Not sure, maybe, e.g. around labeled (and soon default) arguments, documentation generation, maybe somewhere in the LSP as well.
I also find myself often destructuring a pair of values, let #(idx, val) = idx_val or when I need to return a couple of different things when parsing the same input for AoC. For larger output values I create a separate type type Acc { Acc(...) } which is used only once.
hmm, ok
(ideally, not exactly the main focus of my question here though)
I'd also use a tuple or a custom state type for this, don't know of a better way
I think you can relatively trivially modify list.scan:
pub fn scan_state(
over list: List(a),
from initial: acc,
state: state,
with fun: fn(acc, state, a) -> #(acc, state),
) -> List(acc) {
do_scan(list, initial, [], state, fun)
}
fn do_scan(
list: List(a),
accumulator: acc,
accumulated: List(acc),
state: state,
fun: fn(acc, state, a) -> #(acc, state),
) -> List(acc) {
case list {
[] -> reverse(accumulated)
[x, ..xs] -> {
let #(next, next_state) = fun(accumulator, state, x)
do_scan(xs, next, [next, ..accumulated], next_state, fun)
}
}
}
but my thoughts at that point is why not just write your own recurisve solution rather than writing a function to do it
All seem valid! I would probably use fold instead of scan, having an accumulator be a tuple of a List(Bool) and Int
own recursive solution rather than writing a function
Not sure I understand, what's the difference?
as in you inline the function essentially
yeah that's slightly more flexible since you can then modify previous values of th accumulator if necessary (which I did once need to do)