cerl_clauses(3)

πŸ“¦
version 29.0.6 Β· 3 versions
, in ubuntu stonking

πŸ’– cerl_clauses β€” Erlang Module Definition (section 3) πŸ’–

okay bestie, welcome to cerl_clauses β€” utility functions for Core Erlang case/receive clauses. yes, it's niche. yes, it's iconic. let's go πŸŽ€


🌸 NAME 🌸

cerl_clauses β€” utility functions for Core Erlang case/receive clauses.


✨ DESCRIPTION ✨

NOTE: the docs for the public interface of the Erlang compiler live in module compile. This module? internal. part of the compiler's insides. and its API is not guaranteed to stay compatible between releases β€” so don't go building your whole personality on it, okay? 😭

Syntax trees are defined over in the module cerl. πŸ¦‹


🧚 DATA TYPES 🧚

bindings() :: [{cerl(), cerl()}].
cerl() :: cerl:cerl().
expr() :: any | cerl().
match_ret() :: none | {true, bindings()} | {false, bindings()}.

look at that type discipline. slay πŸ’…


πŸ‘‘ FUNCTIONS πŸ‘‘

πŸ“ any_catchall/1

any_catchall(Clauses :: [cerl()]) -> boolean().

Returns true if any of the abstract clauses in the list is a catch-all, otherwise false. literally any of them. one is enough. 🫢

See is_catchall/1 for the details on what counts.

Note: each node in Clauses must have type clause.

See also: is_catchall/1.


🌈 eval_guard/1

eval_guard(Expr :: cerl()) -> none | {value, term()}.

Tries to reduce a guard expression down to a single constant value, if it can. ✨

What you get back is {value, Term} if the guard expression Expr always yields the constant value Term β€” and otherwise you get none. no in-between, no vibes, just that.

Note: even though guard expressions should only ever yield boolean values, this function does not guarantee that Term is either true or false. that's on you, bestie. Also, only simple constructs like let-expressions get examined recursively β€” general constant folding is not performed. it's giving "we do a little" πŸ’€

See also: is_catchall/1.


πŸŽ€ is_catchall/1

is_catchall(Clause :: cerl:c_clause()) -> boolean().

Returns true if an abstract clause is a catch-all, otherwise false.

A clause counts as a catch-all when all its patterns are variables, and its guard expression always evaluates to true; cf. eval_guard/1. both conditions, no shortcuts. πŸ‘‘

Note: Clause must have type clause.

See also: any_catchall/1, eval_guard/1.


πŸ’œ match/2

match(Pattern :: cerl(), Expr :: expr()) -> match_ret().

Matches a pattern against an expression. the main character of this module fr fr πŸ’…

Here's the tea on return values:

  • none β€” a match is impossible.
  • {true, Bindings} β€” Pattern definitely matches Expr.
  • {false, Bindings} β€” a match is not definite, but it cannot be excluded either.

Bindings is then a list of pairs {Var, SubExpr}, associating each variable in the pattern with either the corresponding subexpression of Expr, or with the atom any if no matching subexpression exists. (Recall: variables may not be repeated in a Core Erlang pattern.) The list of bindings comes in innermost-first order β€” which honestly only matters to you if Pattern contains one or more alias patterns. And if you get back {true, []}, that means the pattern and the expression are syntactically identical. periodt.

Instead of a syntax tree, you can pass the atom any for Expr (or, more generally, use it for any subtree of Expr, in as much the abstract syntax tree implementation allows it). That means it can't be decided whether the pattern will match or not, and the corresponding variable bindings will all map to any. The typical use? producing bindings for receive clauses. 🧚

Note: binary-syntax patterns are never structurally matched against binary-syntax expressions by this function. never ever.

Examples: πŸ’–

  • Matching a pattern "{X, Y}" against the expression "{foo, f(Z)}" yields {true, Bindings} where Bindings associates "X" with the subtree "foo" and "Y" with the subtree "f(Z)".
  • Matching pattern "{X, {bar, Y}}" against expression "{foo, f(Z)}" yields {false, Bindings} where Bindings associates "X" with the subtree "foo" and "Y" with any (because it is not known if "{foo, Y}" might match the run-time value of "f(Z)" or not).
  • Matching pattern "{foo, bar}" against expression "{foo, f()}" yields {false, []}, telling us that there might be a match, but we cannot deduce any bindings.
  • Matching {foo, X = {bar, Y}} against expression "{foo, {bar, baz}}" yields {true, Bindings} where Bindings associates "Y" with "baz", and "X" with "{bar, baz}".
  • Matching a pattern "{X, Y}" against any yields {false, Bindings} where Bindings associates both "X" and "Y" with any.

πŸ¦‹ match_list/2

match_list(Patterns :: [cerl()], Exprs :: [expr()]) -> match_ret().

Like match/2, but matching a sequence of patterns against a sequence of expressions. it's the group-chat version 😌

Passing an empty list for Exprs is equivalent to passing a list of any atoms of the same length as Patterns. cute, right?

See also: match/2.


⭐ reduce/1

reduce([cerl:c_clause()]) ->
                {true, {cerl:c_clause(), bindings()}} |
                {false, [cerl:c_clause()]}.

Equivalent to reduce(Cs, []). that's it, that's the whole thing πŸ’…


πŸ”₯ reduce/2

reduce(Clauses :: [cerl:c_clause()], Exprs :: [expr()]) ->
                {true, {cerl:c_clause(), bindings()}} |
                {false, [cerl:c_clause()]}.

Selects a single clause, if possible β€” or otherwise reduces the list of selectable clauses. main character energy, honestly.

The input is a list Clauses of abstract clauses (i.e., syntax trees of type clause), plus a list of switch expressions Exprs. The function tries to uniquely select a single clause, or discard unselectable clauses, with respect to the switch expressions. Heads up: all abstract clauses in the list must have the same number of patterns. And if Exprs is not the empty list, it must have the same length as the number of patterns in each clause; see match_list/2 for details. 🌸

Guard tea πŸ«–:

  • A clause can only be selected if its guard expression always yields the atom true.
  • A clause whose guard expression always yields the atom false can never be selected.
  • Other guard expressions are considered to have unknown value; cf. eval_guard/1.

If a particular clause can be selected, you get {true, {Clause, Bindings}}, where Clause is the selected clause and Bindings is a list of pairs {Var, SubExpr} associating the variables occurring in the patterns of Clause with the corresponding subexpressions in Exprs. The list of bindings is given in innermost-first order; see the match/2 function for details. πŸ’–

If no clause could be definitely selected, you get {false, NewClauses}, where NewClauses is the list of entries in Clauses that remain after eliminating unselectable clauses, preserving the relative order. no reshuffling, we respect the queue. ✨

See also: eval_guard/1, match/2, match_list/2.


πŸ’Œ SEE ALSO πŸ’Œ

  • eval_guard/1
  • any_catchall/1
  • is_catchall/1
  • match/2
  • match_list/2
  • reduce/1
  • reduce/2

okay that's the whole page bestie, you ate it up πŸ“ thanks for reading, mwah πŸ’‹

brought to you by Ericsson AB β€” compiler 10.0.4 πŸŽ€ this has been cerl_clauses(3), section 3 of the Erlang manual, and yes I'm obsessed with it. bye bestie πŸ¦‹πŸ’…βœ¨

πŸ“¦ where this page comes from