A set of questions asked together, answered at exactly the right types.
One request carrying several questions is both cheaper and faster than one request each, and it is the shape the service is designed around. Ask keeps that batching while preserving each question's own answer type:
val (urgent, dept, mood) = client.ask(
Ask(
Question.noul("Does this convey urgency?"),
Question.choice[Dept]("Which team should handle this?"),
Question.score("How frustrated?", Seq("Calm", "Cross", "Livid"))
),
state
)
urgent is a NoulAnswer, dept a ChoiceAnswer[Dept] and mood a ScoreAnswer -- destructured positionally, with no casts and no lookups by string. The map-based algebra.Evaluation remains available for cases where the questions are not known statically.
Question keys are generated positionally, so callers never name them. Use withKeys if you need them to match something else.
Project a response back into the positional answer tuple.
Project a response back into the positional answer tuple.
This is the only place in the library that casts. Both are justified by the same fact: the list is built by walking the very tuple that Ask.Answers is computed from, in the same order, so element i has the type the match type assigns to position i.