Skip to main content

linkrs_core/
function.rs

1//! Function-name classification for plan analysis.
2//!
3//! Identifies functions whose arguments are evaluated per element of a
4//! list (lambda-style evaluation). Plan passes that reason about
5//! evaluation order (for example factorization flattening) consult this
6//! module instead of hardcoding function names, so the classification
7//! stays consistent wherever it is used.
8
9/// Names evaluated per list element with the lambda at argument index 1.
10///
11/// `list_extract` takes a list and an index rather than a lambda, but it
12/// has historically received the same per-element treatment; that
13/// treatment is preserved here to avoid changing flattening behavior.
14/// `list_any`, `list_all` and `list_single` are predicate variants that
15/// evaluate the lambda per element like `list_filter`.
16const LIST_LAMBDA_NAMES: [&str; 7] = [
17    "list_filter",
18    "list_extract",
19    "list_transform",
20    "list_reduce",
21    "list_any",
22    "list_all",
23    "list_single",
24];
25
26/// Report whether a function evaluates an argument per list element.
27///
28/// Matching is case-insensitive to mirror binder normalization.
29pub fn is_list_lambda(name: &str) -> bool {
30    LIST_LAMBDA_NAMES.contains(&name.to_lowercase().as_str())
31}
32
33/// Argument position of the per-element expression for a list lambda.
34///
35/// Returns `None` for functions without per-element evaluation.
36pub fn list_lambda_arg_index(name: &str) -> Option<usize> {
37    if is_list_lambda(name) {
38        Some(1)
39    } else {
40        None
41    }
42}
43
44#[cfg(test)]
45mod tests {
46    use super::*;
47
48    #[test]
49    fn known_lambdas_match_case_insensitively() {
50        assert!(is_list_lambda("list_filter"));
51        assert!(is_list_lambda("LIST_TRANSFORM"));
52        assert!(is_list_lambda("List_Extract"));
53        assert!(is_list_lambda("list_reduce"));
54        assert!(is_list_lambda("list_any"));
55        assert!(is_list_lambda("LIST_ALL"));
56        assert!(is_list_lambda("List_Single"));
57    }
58
59    #[test]
60    fn eager_functions_do_not_match() {
61        assert!(!is_list_lambda("list_append"));
62        assert!(!is_list_lambda("list_contains"));
63        assert!(!is_list_lambda("abs"));
64        assert!(!is_list_lambda(""));
65    }
66
67    #[test]
68    fn lambda_arg_index_is_second_position() {
69        assert_eq!(list_lambda_arg_index("list_filter"), Some(1));
70        assert_eq!(list_lambda_arg_index("list_transform"), Some(1));
71        assert_eq!(list_lambda_arg_index("list_append"), None);
72    }
73}