3 ms·
Genuine question: What design pattern works best here: Let's say I want to write small functions that do one thing very well: args = {LLM parameters, e.g.
by behnamoh 3y ago
Genuine question: What design pattern works best here:
Let's say I want to write small functions that do one thing very well:
args = {LLM parameters, e.g., prompt}
1. foo(args): calls the LLM API with args
2. goo (foo(args)): uses backoff (retry) and makes sure the output is JSON
3. hoo(goo(foo(args))): extracts and desers the JSON
At any point, things could go wrong. I could use a monadic approach and turn each of these functions into a monad:
1. foo: args -> Maybe(API_res)
2. goo: Maybe(API_res) -> Maybe(JSON)
3. hoo: Maybe(JSON) -> Maybe(dict)
But before I knew about monads, I thought: wouldn't be cool if when a function goes wrong and needs to be called again, it had access to its "parent" function which called it? Like:
Currently args is only passed to foo. What if, depending on how things went wrong, goo needed to see args?
One approach is to make foo pass its args as well:
foo: args -> args, output
Then goo would take that and do something with it. But what if now hoo also needed to know about args to make sure the extracted JSON conforms to the JSON schema mentioned in args? Now we'd have to do:
foo: args -> args, output
goo: args, output -> args, output, JSON
goo: args, output, JSON -> dict (deserialized JSON)
I think this is not "elegant". Is there any better solution?
- nh23423fefe 3y agofoo should hold the args and be a command object, not a result type goo should take foo as argument and delegate to the command in its loop hoo shouldn't be a Maybe. if you want that function then lift hoo instead of writing it, that's fmap hoo