Am 23.03.26 um 01:07 schrieb Akhra Gannon:
honestly, the way you've laid it out looks perfectly reasonable to me! it generally follows the principle ot "parse, don't validate" laid out here: https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t- validate/ <https://lexi-lambda.github.io/blog/2019/11/05/parse-don-t- validate/>
Heh. Took me long enough to arrive at the same conclusions, though it was more an intuitive process than the clear(ish) explanations there.
the only core change I might make is to remove the payload from ConfigData and use a tuple of (SourceIndex, a) instead, so you can operate on one without examining the other. this lets you do all the source-related analysis with monomorphic code; and in cases where the final payload type is unchanged, you can just discard the tuple wrapper to finalize.
at the top level, for each final-config item I'd imagine the process would (in Haskell) look something like:
finalizeConfigValue :: (a -> Maybe b) -> [(SourceIndex, a)] -> Maybe b finalizeConfigValue valueParser = listToMaybe . mapMaybe (valueParser . snd) . sortOn fst
with an Ord instance on SourceIndex, and the Maybe output representing failure of all candidates to parse (you could also use defaulting and/or exceptions) Okay... I have to read this carefully.
Just to verify I understood it correctly: It's declaring function finalizeConfigValue, with two parameters (disregarding currying), one is a function a -> Maybe b, second is a list of SourceIndex/a tuples; result is a Maybe B. What kind of type is a? A raw parse tree as delivered from the yaml parser, i.e. a hierarchical blob of Maps, Lists, and Strings for terminals? (I decided to configure the parser for "everything is a string" because (a) no real need for numbers in my use case and (b) possibly YAML has some weird definition of what's number and what's a string.) What does listToMaybe do? Hm. Which parameter does it pick up, the first or the second? I'm not sure how dot notation and currying interact. valueParser seems composed with snd ("second") - ah ok, this is essentially processing an event list/stream ("stream" would be a list that happens to be lazy in Haskell land). Not sure what the mapMaybe serves. I guess it's dealing with error cases or some such, but I can't infer what kind of cases that would be and what the intended effect it (my lack of Haskell knowledge shows again). Ah right. The (sortOn fst) somehow gets routed to the event stream. Not sure why that's needed, as the inputs should already be sorted by source position, but maybe you're thinking about situations where things are processed in a different order than they are read - doesn't happen in my use case, so maybe that's why I'm guessing instead of understanding, I'm blocked by differences in implicit assumptions. I guess. I believe the main block to me understanding such code is that I don't know how many parameters a function has - or, in the currying perspective, what order a function is. It's a great way to write and reason about higher-level code, but for noobs like me it's making it really hard to understand what's going on - I suspect it's because I don't know what order the functions inside the function's body are (resp. how many parameters they take). I also suspect it's really an issue with dot-notation pipelines like above: If you don't know the order and return types of the functions being composed, you have no clue about what function is working on how many parameters - might be two, or might be just one and the extra parameter is accepted later in the queue (maybe? I am sooo unsure here...) Oh my. I guess I'm going to learn a whole lot here. Which is exactly the point, actually :-) Regards, Jo