### Install MLStyle.jl Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/how.md Instructions for installing the MLStyle.jl package using the Julia package manager. ```julia using Pkg Pkg.add("MLStyle") ``` -------------------------------- ### Julia Selector Usage Examples Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Presents practical examples of valid selectors used within the Julia query language, showcasing field access, predicate usage, and expression binding. ```Julia _.foo, _.1, _.(startswith("bar"), !endswith("foo")), x + _.foo, let y = _.foo + y; y + _.(2) end ``` -------------------------------- ### ADT Examples with Pattern Matching Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/adt.md Illustrates practical examples of using the `@data` macro for ADT definitions and demonstrates how to use the `@match` macro for pattern matching against these ADTs. Includes assertions to verify type relationships. ```julia @data E begin E1 E2(Int) end @assert E1 isa E && E2 <: E @match E1 begin E2(x) => x E1 => 2 end @match E2(10) begin E2(x) => x E1 => 2 end ``` ```julia @data A begin A1(Int, Int) A2(a :: Int, b :: Int) A3(a, b) end @data B{T} begin B1(T, Int) B2(a :: T) end @data C{T} begin C1(T) C2{A} :: Vector{A} => C{A} end abstract type DD end some_type_to_int(x::Type{Int}) = 1 some_type_to_int(x::Type{<:Tuple}) = 2 @data D{T} <: DD begin D1{T} :: Int => D{T} D2{A, B} :: (A, B, Int) => D{Tuple{A, B}} D3{A, N} :: A => D{Array{A, N}} where {N = some_type_to_int(A)} end ``` -------------------------------- ### MLStyle.jl Data Query Example Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md This example demonstrates a typical data querying workflow using MLStyle.jl macros with DataFrames. It showcases filtering with @where, grouping with @groupby, conditional aggregation with @having, and selecting/transforming columns with @select. ```julia using Enums @enum TypeChecking Dynamic Static include("MQuery.jl") df = DataFrame( Symbol("Type checking") => [Dynamic, Static, Static, Dynamic, Static, Dynamic, Dynamic, Static], :name => ["Julia", "C#", "F#", "Ruby", "Java", "JavaScript", "Python", "Haskell"]), :year => [2012, 2000, 2005, 1995, 1995, 1995, 1990, 1990] ) df |> @where !startswith(_.name, "Java"), @groupby _."Type checking" => TC, endswith(_.name, "#") => is_sharp, @having TC === Dynamic || is_sharp, @select join(_.name, " and ") => result, _.TC => TC ``` -------------------------------- ### Julia Enum Pattern Matching Setup Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the setup for enabling pattern matching with Julia enums. It involves defining an enum, marking it as an enum for MLStyle using `MLStyle.is_enum`, and providing the matching logic. ```julia-console julia> using MLStyle julia> @enum E E1 E2 # mark E1, E2 as non-capturing patterns julia> MLStyle.is_enum(::E) = true # tell the compiler how to match E1 and E2 ``` -------------------------------- ### Active Patterns with Regex and Custom Logic Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/preview.md Demonstrates MLStyle.jl's implementation of active patterns, which allow pattern matching based on arbitrary boolean conditions or function calls. Includes examples for matching strings with regular expressions and checking for even numbers. ```julia @active Re{r :: Regex}(x) begin ret = match(r, x) ret !== nothing && return Some(ret) end @match "123" begin Re{r"\d+"}(x) => x _ => @error "" end # RegexMatch("123") @active IsEven(x) begin x % 2 == 0 end @match (1, 2, 3) begin (1, IsEven, a) => a end # => 3 ``` -------------------------------- ### Julia Query Language Syntax Example Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Demonstrates the high-level syntax for a Julia query language, including clauses like @select, @where, @groupby, and @orderby, inspired by T-SQL. ```Julia df |> @select selectors..., @where predicates…, @groupby mappings…, @orderby mappings…, @having mappings…, @limit JuliaExpr ``` -------------------------------- ### Julia Stacked @select Clause Example Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Demonstrates how stacked @select clauses are handled in the code generation process for the Julia query language. ```Julia df |> @select _, _.foo + 1, => foo1, ``` -------------------------------- ### Select Statement Code Generation with Typed Columns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Shows code generation for a `select` statement after introducing `IN_TYPES` to handle column types effectively. It includes an example of using the `@select` macro. ```julia @select _, _.foo + 1 # `@select _` is regarded as `SELECT *` in T-SQL. ``` -------------------------------- ### MLStyle Literal Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Illustrates how to use literal values (integers, booleans, strings, etc.) as patterns to check for exact equality with the input data. It shows a practical example and provides an equivalent if-elseif-else structure for clarity. ```julia ```julia-console julia> @match 10 begin 1 => "wrong!" 2 => "wrong!" 10 => "right!" end "right!" ``` ``` ```julia ```julia VALUE = 10 if VALUE === 1 "wrong!" elseif VALUE === 2 "wrong!" elseif VALUE === 10 "right!" else error("matching non-exhaustive") end ``` ``` -------------------------------- ### Custom Pattern API: MLStyle.pattern_uncall Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Details the `MLStyle.pattern_uncall` API for defining custom patterns. It explains the arguments: `pat_obj`, `expr_to_pat`, `type_params`, `type_args`, and `args`. It also provides a usage example for compiling AST into patterns. ```julia - `MLStyle.pattern_uncall` - args: - `pat_obj` your pattern object, should be a global variable in some module. The pattern is visible if and only if the global variable is visible in current scope. - `expr_to_pat::Function` this is provided for you to transform an AST into patterns, for instance, `expr_to_pat(:([a, 1]))`, with which you create a pattern same as `[a, 1]`. - `type_params` - `type_args` - `args` - usage We compile the AST `pat_obj{c, d}(e, f) where {a, b}` into the pattern with `MLStyle.pattern_uncall(pat_obj, expr_to_pat, [:a, :b], [:c, :d], [:e, :f])`. ``` -------------------------------- ### Generalized Algebraic Data Types (GADTs) with MLStyle Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/preview.md Illustrates the definition and usage of Generalized Algebraic Data Types (GADTs) using MLStyle.jl's @data macro. GADTs allow type parameters to be associated with constructors, enabling more expressive type definitions, shown here with an expression language. ```julia @use GADT @data public Exp{T} begin Sym{A} :: Symbol => Exp{A} Val{A} :: A => Exp{A} Lam{A, B} :: (Symbol, Exp{B}) => Exp{Fun{A, B}} If{A} :: (Exp{Bool}, Exp{A}, Exp{A}) => Exp{A} App{A, B, A′<:A} :: (Exp{Fun{A, B}}, Exp{A′}) => Exp{B} end ``` -------------------------------- ### Example Evaluation of Arithmetic Expression Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/adt.md Demonstrates the evaluation of a sample arithmetic expression: 2 - (20 / (2 * 5)) using the `eval_arith` function. ```julia eval_arith( Minus( Number(2), Divide(Number(20), Mult(Number(2), Number(5))))) ) ``` -------------------------------- ### Using Enum-like Patterns in MLStyle Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/preview.md Shows how to make ADT constructors behave like enums for pattern matching by implementing MLStyle.is_enum. This allows matching against constructors directly (e.g., Paper) instead of instances (e.g., Paper()). ```julia # use pattern `A()` with the syntax `A` MLStyle.is_enum(::Type{Rock}) = true MLStyle.is_enum(::Type{Paper}) = true MLStyle.is_enum(::Type{Scissors}) = true play(a::Shape, b::Shape) = @match (a, b) begin (Paper, Rock) => "Paper Wins!"; (Rock, Scissors) => "Rock Wins!"; (Scissors, Paper) => "Scissors Wins!"; (a, b) => a == b ? "Tie!" : play(b, a) end ``` -------------------------------- ### Groupby Operation with String Matching in Julia Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Explains how to use the @groupby macro to group data based on a condition applied to a field, specifically checking if a string field starts with a given prefix. It also shows how to define the output group key. ```julia let IN_FIELDS, IN_SOURCE = process(df), idx_of_name = findfirst(==(:name), IN_FIELDS), @inline FN(_name) = (startswith(_.name, "Ruby"), ) GROUPS = Dict() # the type issues will be discussed later. for RECORD in IN_SOURCE _name = RECORD[idx_of_name] GROUP_KEY = (is_ruby, ) = FN(_name) AGGREGATES = get!(GROUPS, GROUP_KEY) do Tuple([] for _ in IN_FIELDS) end push!.(AGGREGATES, RECORD) end [[:is_ruby]; IN_FIELDS], ((k..., v...) for (k, v) in GROUPS) end ``` -------------------------------- ### Julia AST Manipulation with MLStyle Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/preview.md Demonstrates using MLStyle.jl's @λ (lambda) macro and @match for deconstructing and transforming Julia Abstract Syntax Trees (ASTs). It includes a function `rmlines` to remove line number nodes and a pattern match to extract struct definitions. ```julia rmlines = @λ begin e :: Expr => Expr(e.head, filter(x -> x !== :magic_symbol_oh_really, map(rmlines, e.args))...) :: LineNumberNode => :magic_symbol_oh_really a => a end expr = quote struct S{T} a :: Int b :: T end end |> rmlines @match expr begin quote struct $name{$tvar} $f1 :: $t1 $f2 :: $t2 end end => quote struct $name{$tvar} $f1 :: $t1 $f2 :: $t2 end end |> rmlines == expr end ``` -------------------------------- ### Extracting from Julia ASTs with MLStyle.jl Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/why.md Demonstrates how MLStyle.jl can be used to extract components from Julia Abstract Syntax Trees (ASTs) using pattern matching. This example shows how to match a function call expression and extract the function name. ```julia f = some_thing ex = :($f(a, b)) f == @match ex begin :($f(a, b)) => f end ``` -------------------------------- ### Julia Code Generation with Macros Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md This snippet demonstrates how to generate Julia code using macros. It defines a structure for generating functions with specific arguments, types, and bodies, utilizing `quote` and `let` for code construction. The generated code includes type parameters and a `build_result` function call. ```julia fields = $get_fields($ARG), types =$type_unpack($length(fields), $eltype(iter)) (fields, types, iter) end end fn_body = foldl(rec(ops), init = init) do last, mk mk(last) end quote @inline function ($ARG :: $TYPE_ROOT, ) where {$TYPE_ROOT} let ($IN_FIELDS, $IN_TYPES, $IN_SOURCE) = $fn_body $build_result( $TYPE_ROOT, $IN_FIELDS, $IN_TYPES, $IN_SOURCE ) end end end end end ``` -------------------------------- ### MLStyle And-Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Explains the `pat1 && pat2` syntax for combining multiple patterns that must all match the input. Also covers the 'As-Pattern' variant (`pat && x`) for capturing the entire matched value. ```julia ```julia-console julia> @match 2 begin x::Int && if x < 5 end => √(5 - x) end 1.7320508075688772 ``` ``` ```julia ```julia julia> @match (1, 2) begin (a, b) && c => c[1] == a && c[2] == b end true ``` ``` -------------------------------- ### MLStyle @match Macro Basic Syntax Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the fundamental usage of the @match macro for conditional execution based on data patterns. It explains the sequential matching process and error handling for non-exhaustive matches. Also covers the simplified syntax for single patterns in newer versions. ```julia ```julia @match data begin pattern1 => result1 pattern2 => result2 ... patternn => resultn end ``` ``` ```julia ```julia @match data pattern => result ``` ``` -------------------------------- ### Active Pattern: IsLessThan0 (0-ary) Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Implements a 0-ary active pattern `IsLessThan0` that returns a Boolean. It checks if a given number is less than 0. The example shows matching against positive and negative numbers. ```julia # 0-ary deconstruction: return Bool @active IsLessThan0(x) begin x < 0 end @match 10 begin IsLessThan0() => :a _ => :b end # b @match -10 begin IsLessThan0() => :a _ => :b end # :a ``` -------------------------------- ### ADT with Specified Field Names Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/adt.md Illustrates how to specify field names for subtypes within an ADT definition using the `@data` macro. The example shows the generated Julia code with named fields for each constructor. ```julia abstract type T end struct C1 <: T a b c end struct C2 <: T x y end ``` -------------------------------- ### MLStyle.jl Performance Data Source: https://github.com/thautwarm/mlstyle.jl/blob/main/stats/bench-datatype.txt This data represents the performance benchmark results for MLStyle.jl, Rematch, and Match.jl. It details the mean execution time in seconds for each implementation across different test cases. ```text 21×3 DataFrame Row │ time_mean implementation case │ Float64 Symbol Symbol ─────┼─────────────────────────────────── 1 │ 10.877 MLStyle s1 2 │ 11.0804 Rematch s1 3 │ 14.1355 Match.jl s1 4 │ 9.5591 MLStyle s2 5 │ 9.93765 Rematch s2 6 │ 38.9031 Match.jl s2 7 │ 14.1924 MLStyle s3 8 │ 16.6543 Rematch s3 9 │ 13.4356 Match.jl s3 10 │ 25.8738 MLStyle s4 11 │ 206.839 Rematch s4 12 │ 55.9708 Match.jl s4 13 │ 11.1525 MLStyle s5 14 │ 19.3045 Rematch s5 15 │ 12.3666 Match.jl s5 16 │ 15.0801 MLStyle s6 17 │ 14.8673 Rematch s6 18 │ 13.5743 Match.jl s6 19 │ 25.8602 MLStyle _ 20 │ 28.4733 Rematch _ 21 │ 24.6885 Match.jl _ ``` -------------------------------- ### String Macro Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the use of string macro patterns for matching raw strings and regular expressions within the @match macro. This allows for flexible pattern matching based on string content. ```julia-console julia> @match raw"$$$" begin raw"$$$" => 1 end 1 julia> @match "123" begin r"^\d+$" => 1 end 1 ``` -------------------------------- ### MLStyle.jl Macro Expansion for @match Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the expanded code generated by the @match macro in MLStyle.jl for a given input, illustrating how pattern matching is translated into conditional logic and variable assignments. ```julia julia> MLStyle.enum_matcher(e::E, expr) = :($e === $expr) julia> x = E2 julia> @match x begin E1 => "match E1!" E2 => "match E2!" end "match E2!" x = E1 julia> @macroexpand @match x begin E1 => "match E1!" E2 => "match E2!" end :(let var"##return#261" = nothing var"##263" = x if E1 === var"##263" var"##return#261" = let "match E1!" end $(Expr(:symbolicgoto, Symbol("####final#262#264"))) end if E1 === var"##263" var"##return#261" = let "match E2!" end $(Expr(:symbolicgoto, Symbol("####final#262#264"))) end (error)("matching non-exhaustive, at #= ... =#") $(Expr(:symboliclabel, Symbol("####final#262#264"))) var"##return#261" end) ``` -------------------------------- ### MLStyle GuardBy Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Illustrates the `GuardBy(f)` pattern, which matches an input only if the predicate function `f` returns true when applied to the input. Provides examples using both named functions and lambda expressions as predicates. ```julia ```julia function pred(x) x > 5 end @match x begin GuardBy(pred) => 5 - x # only succeeds when x > 5 _ => 1 end ``` ``` ```julia ```julia @match x begin GuardBy(x -> x > 5) => 5 - x # only succeeds when x > 5 _ => 1 end ``` ``` -------------------------------- ### Subtyping with @data Macro Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/adt.md Demonstrates how to create ADTs that subtype existing abstract types using the standard Julia `<:` syntax within the `@data` macro. It includes an example of a generic ADT `ShortVec` that subtypes `AbstractVector`. ```julia abstract type ShortVec{T} <: AbstractVector{T} end struct V0 <: ShortVec{Any} end struct V1{T} <: ShortVec{T} _1::T end struct V2{T} <: ShortVec{T} _1::T _2::T end ``` -------------------------------- ### Julia Formalized Selector Syntax (E-BNF) Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Provides a formal definition of the selector syntax using Extended Backus-Naur Form (E-BNF), outlining the structure of field predicates and query expressions. -------------------------------- ### MLStyle Type Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the use of type patterns (`::Type`) to match inputs based on their type. Shows how to combine type patterns with capturing patterns (`x::Type`) to bind typed values to variables. ```julia ```julia-console julia> @match 1 begin ::Float64 => nothing b :: Int => b _ => nothing end 1 ``` ``` -------------------------------- ### Active Pattern with Enum: IsEven Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Shows how to use active patterns with Julia enums. It defines an `IsEven` active pattern and marks the enum type `E` as an enum using `MLStyle.is_enum`. The example matches an even number. ```julia @active IsEven(x) begin x % 2 === 0 end MLStyle.is_enum(::Type{IsEven}) = true @match 6 begin IsEven => :even _ => :odd end # :even ``` -------------------------------- ### MLStyle Or Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates the `pat1 || pat2` syntax for creating patterns that match if either of the constituent patterns succeeds. Shows how Or-patterns can be nested and spread across multiple lines for complex matching scenarios. ```julia ```julia julia> @match 2 begin 0 || 1 => "01" 2 || 3 => "23" end "23" ``` ``` ```julia ```julia julia> @match 3 begin (0 || 1) || (2 || 3) => "0123" end "0123" ``` ``` ```julia ```julia test(num) = @match num begin ::Float64 || 0 || 1 || 2 => true _ => false end ``` ``` -------------------------------- ### MLStyle.jl Type Pattern Matching with 'where' Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Illustrates the correct usage of type parameters with the 'where' syntax in MLStyle.jl's @match macro for advanced type pattern matching. It shows how to extract type information correctly. ```julia @match 1 begin a :: T where T => T end # => Int64 ``` -------------------------------- ### ADT with Singleton Instances Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/adt.md Explains how to define ADTs with singleton instances (types with no fields) using the `@data` macro. The example shows the generated Julia code for singletons `a` and `b`, including the creation of private types and constants. ```julia abstract type T end struct _A <: T end const a = _A() struct _B <: T end const b = _B() ``` -------------------------------- ### Active Pattern: LessThan0 (1-ary) Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Implements a 1-ary active pattern `LessThan0` that returns `Some(x)` if the number is less than 0, and `nothing` otherwise. This allows capturing the value if the pattern matches. The example demonstrates capturing the negative value. ```julia # 1-ary deconstruction: return Union{Some{T}, Nothing} @active LessThan0(x) begin if x >= 0 nothing else Some(x) end end @match 15 begin LessThan0(a) => a _ => 0 end # 0 @match -15 begin LessThan0(a) => a _ => 0 end # -15 ``` -------------------------------- ### Basic @switch Usage Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/switch.md Demonstrates the basic usage of the @switch macro for pattern matching and variable assignment within a julia code block. It shows how to capture values from a tuple and assign them to outer variables. ```julia var = 1 x = (33, 44) @switch x begin @case (var, _) println(var) end ``` -------------------------------- ### Rock Paper Scissors with MLStyle Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/preview.md Defines an algebraic data type 'Shape' and uses MLStyle's @match macro for pattern matching to determine the winner of a Rock Paper Scissors game. It demonstrates basic ADT definition and pattern matching. ```julia using MLStyle @data Shape begin # Define an algebraic data type Shape Rock() Paper() Scissors() end # Determine who wins a game of rock paper scissors with pattern matching play(a::Shape, b::Shape) = @match (a, b) begin (Paper(), Rock()) => "Paper Wins!"; (Rock(), Scissors()) => "Rock Wins!"; (Scissors(), Paper()) => "Scissors Wins!"; (a, b) => a == b ? "Tie!" : play(b, a) end ``` -------------------------------- ### Julia Selector Syntax Variations Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Illustrates different ways to define selectors in the Julia query language, including field access, expression binding, and predicate-based selection. ```Julia _.x / _.(1) _."x" x + _.x => a / => "a" _.(predicate1(args...), !predicate2(args2..., ), ...) ``` -------------------------------- ### Parametric Active Pattern: Re{r} Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Implements a parametric active pattern `Re{r}` where `r` is a Regex type parameter. This pattern matches a string against the provided regex and returns the match object if successful. The example shows matching a string with a regex. ```julia @active Re{r :: Regex}(x) begin res = match(r, x) if res !== nothing # use explicit `if-else` to emphasize the return should be Union{T, Nothing}. Some(res) else nothing end end @match "123" begin Re{r"\d+"}(x) => x _ => @error "" end # RegexMatch("123") ``` -------------------------------- ### Benchmark MLStyle.jl vs Match.jl Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/benchmark.md Benchmarks MLStyle.jl against Match.jl, demonstrating performance differences in pattern matching scenarios. The benchmark script is available at bench-vs-match.jl. ```julia include("matrix-benchmark/bench-vs-match.jl") ``` -------------------------------- ### Parametric Active Pattern: SplitVecAt{N} Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates a parametric active pattern `SplitVecAt{N}` where `N` is an integer type parameter. This pattern splits a vector at the Nth element. The example shows splitting a vector using a specified parameter `N=2`. ```julia @active SplitVecAt{N::Int}(x) begin (x[1:N], x[N+1:end]) end @match [1, 2, 3, 4, 7] begin SplitVecAt{2}(a, b) => (a, b) end # ([1, 2], [3, 4, 7]) ``` -------------------------------- ### MLStyle.jl vs Match.jl Performance Data Source: https://github.com/thautwarm/mlstyle.jl/blob/main/stats/bench-versus-match.txt This data represents the benchmark results for MLStyle.jl and Match.jl. It shows the average time taken for different implementations (MLStyle Expr-pattern, MLStyle AST-pattern, Match.jl) across various test cases (s1-s6). The 'time_mean' column indicates the execution time in seconds. ```Julia 18×3 DataFrame Row │ time_mean implementation case │ Float64 Symbol Symbol ─────┼───────────────────────────────────────── 1 │ 49.2341 MLStyle Expr-pattern s1 2 │ 37.9193 MLStyle AST-pattern s1 3 │ 53.5103 Match.jl s1 4 │ 51.1928 MLStyle Expr-pattern s2 5 │ 35.7297 MLStyle AST-pattern s2 6 │ 53.7347 Match.jl s2 7 │ 50.504 MLStyle Expr-pattern s3 8 │ 49.1989 MLStyle AST-pattern s3 9 │ 53.1803 Match.jl s3 10 │ 30.1107 MLStyle Expr-pattern s4 11 │ 5.9283 MLStyle AST-pattern s4 12 │ 30.2508 Match.jl s4 13 │ 30.6134 MLStyle Expr-pattern s5 14 │ 14.9725 MLStyle AST-pattern s5 15 │ 32.9388 Match.jl s5 16 │ 34.0904 MLStyle Expr-pattern s6 17 │ 33.0146 MLStyle AST-pattern s6 18 │ 37.7301 Match.jl s6 ``` -------------------------------- ### MLStyle Visitor for Field Access Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Implements a visitor pattern using MLStyle.jl's `@match` macro to process expressions involving field access, such as `_.x`, `_. (1)`, or `_.("x")`. It handles both integer and string/symbol based field lookups, optimizing symbol generation using `fields` and `assigns` dictionaries. ```julia function mk_visit(fields :: Dict{Any, Field}, assigns :: OrderedDict{Symbol, Any}) visit = expr -> @match expr begin Expr(:. , :_, q :: QuoteNode) && Do(a = q.value) || Expr(:., :_, Expr(:tuple, a)) => @match a begin a :: Int => let field = get!(fields, a) do var_sym = gen_sym(a) Field( a, Expr(:ref, RECORD, a), var_sym, Expr(:ref, IN_TYPES, a) ) end field.var end ::String && Do(b = Symbol(a)) || b::Symbol => let field = get!(fields, b) do idx_sym = gen_sym() var_sym = gen_sym(b) assigns[idx_sym] = Expr(:call, findfirst, x -> x === b, IN_FIELDS) Field( b, Expr(:ref, RECORD, idx_sym), var_sym, Expr(:ref, IN_TYPES, idx_sym) ) end field.var end end Expr(head, args...) => Expr(head, map(visit, args)...) a => a end end ``` -------------------------------- ### Active Pattern: SplitVecAt2 ((n+2)-ary) Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Implements an n+2-ary active pattern `SplitVecAt2` that splits a vector into two parts. It returns a tuple containing the first two elements and the rest of the vector. The example shows splitting a vector and capturing the two parts. ```julia # (n+2)-ary deconstruction: return Tuple{E1, E2, ...} @active SplitVecAt2(x) begin (x[1:2], x[2+1:end]) end @match [1, 2, 3, 4, 7] begin SplitVecAt2(a, b) => (a, b) end # ([1, 2], [3, 4, 7]) ``` -------------------------------- ### Let Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Explains the concept of Let Patterns, which allow binding variables within a pattern match without altering existing variable bindings. This is useful for introducing new variables scoped to the pattern match. ```julia-console julia> @match 1 begin let x = 2 end => x end 2 ``` -------------------------------- ### MLStyle.jl Benchmark Results Source: https://github.com/thautwarm/mlstyle.jl/blob/main/stats/bench-tuple.txt DataFrame showing the mean execution time (time_mean) in milliseconds for different implementations (MLStyle, Rematch, Match.jl, HandWritten) across various test cases (spec1 to spec5 and a general case '_'). This data highlights the performance characteristics of MLStyle.jl relative to its competitors. ```Julia 24×3 DataFrame Row │ time_mean implementation case │ Float64 Symbol Symbol ─────┼──────────────────────────────────── 1 │ 165.953 MLStyle spec1 2 │ 286.78 Rematch spec1 3 │ 190.29 Match.jl spec1 4 │ 179.69 HandWritten spec1 5 │ 2713.54 MLStyle spec2 6 │ 3523.3 Rematch spec2 7 │ 2868.37 Match.jl spec2 8 │ 2641.46 HandWritten spec2 9 │ 3328.09 MLStyle spec3 10 │ 4159.84 Rematch spec3 11 │ 4094.66 Match.jl spec3 12 │ 3514.94 HandWritten spec3 13 │ 1366.72 MLStyle spec4 14 │ 1851.44 Rematch spec4 15 │ 1783.84 Match.jl spec4 16 │ 13473.0 HandWritten spec4 17 │ 10.6664 MLStyle spec5 18 │ 10.9764 Rematch spec5 19 │ 11.3479 Match.jl spec5 20 │ 11.1488 HandWritten spec5 21 │ 26.6849 MLStyle _ 22 │ 25.4721 Rematch _ 23 │ 26.4363 Match.jl _ 24 │ 24.2934 HandWritten _ ``` -------------------------------- ### Capture Pattern from MLStyle.Modules.AST Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/capture.md Demonstrates the 'Capture' pattern from MLStyle.Modules.AST for capturing variables from an Abstract Syntax Tree (AST) and accessing them via scope information. This pattern allows for cleaner variable management compared to traditional methods. ```julia using MLStyle.Modules.AST println(Capture) # => Capture @match :(a + b + c) begin :($a + $b + $c) && Capture(scope) => scope end # Dict{Symbol,Symbol} with 3 entries: # :a => :a # :b => :b # :c => :c ``` -------------------------------- ### LambdaCases.jl Lambda Functions with Pattern Matching Source: https://github.com/thautwarm/mlstyle.jl/blob/main/src/StandardPatterns/README.md Provides two ways to define lambda functions with pattern matching support using the @λ macro. ```julia xs = [(1, 2), (1, 3), (1, 4)] map((@λ (1, x) => x), xs) # => [2, 3, 4] (2, 3) |> @λ begin 1 => 2 2 => 7 (a, b) => a + b end # => 5 ``` -------------------------------- ### DataFrame Generation from Query Clauses Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Demonstrates generating a DataFrame from query clauses like field names and lazy computation. It iterates through source data and pushes elements into corresponding fields to construct the DataFrame. ```julia function (ARG :: DataFrame) (IN_FIELDS, IN_SOURCE) = let IN_FIELDS, IN_SOURCE = ... ... end res = Tuple([] for _ in IN_FIELDS) for each in IN_SOURCE push!.(res, each) end DataFrame(collect(res), IN_FIELDS) end ``` -------------------------------- ### DataFrame Column Type Refinement Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Illustrates the refinement of DataFrame column types using a framework for query language implementation. It addresses issues with `Vector{Any}` columns and the inefficiency of calculating super types. ```julia res = Tuple([] for _ in IN_FIELDS) for each in SOURCE push!.(res, each) end DataFrame(collect(res), collect(IN_FIELDS)) ``` -------------------------------- ### Select Operation in Julia Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Demonstrates how to use the @select macro for transforming data. It shows how to add a constant to a field and rename the output column. ```julia let (IN_FIELDS, IN_SOURCE) = process(df), idx_of_foo1 = findfirst(==(:foo1), IN_FIELDS), @inline FN(_foo1) = (_foo1 + 2, ) [:foo2], ( let _foo1 = RECORD[idx_of_foo1] FN(_foo1) end for RECORD in IN_SOURCE ) end ``` -------------------------------- ### Do-Patterns and Many-Patterns Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Illustrates the usage of Do-Patterns for introducing side-effects and Many-Patterns for matching repeated elements within a sequence. These patterns can be combined for complex matching scenarios. ```julia @match [1, 2, 3] begin Many(::Int) => true _ => false end # true @match [1, 2, 3, "a", "b", "c", :a, :b, :c] begin Do(count = 0) && Many[ a::Int && Do(count = count + a) || ::String || ::Symbol && Do(count = count + 1) ] => count end # 9 ``` -------------------------------- ### Macro Flattening and Operation Extraction Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/tutorials/query-lang.md Demonstrates how MLStyle.jl flattens macro calls, extracts operations, and handles nested macros. It defines helper functions to identify macros and process macrocall expressions, transforming them into a structured list of operations and their arguments. ```julia function generate_select end function generate_where end function generate_groupby end function generate_orderby end function generate_having end function generate_limit end const registered_ops = Dict{Symbol, Any}( Symbol("@select") => generate_select, Symbol("@where") => generate_where, Symbol("@groupby") => generate_groupby, Symbol("@having") => generate_having, Symbol("@limit") => generate_limit, Symbol("@orderby") => generate_orderby ) function get_op(op_name) registered_ops[op_name] end ismacro(x :: Expr) = Meta.isexpr(x, :macrocall) ismacro(_) = false function flatten_macros(node :: Expr) @match node begin Expr(:macrocall, op :: Symbol, ::LineNumberNode, arg) || Expr(:macrocall, op :: Symbol, arg) => @match arg begin Expr(:tuple, args...) || a && Do(args = [a]) => @match args begin [args..., tl && if ismacro(tl) end] => [(op |> get_op, args), flatten_macros(tl)...] _ => [(op |> get_op, args)] end end end end ``` -------------------------------- ### Type Matching with Constraints Source: https://github.com/thautwarm/mlstyle.jl/blob/main/docs/syntax/pattern.md Demonstrates matching against types with specific constraints using `@match`. Shows how to match a type `T` and a type `T` that is a subtype of `Number` or `AbstractFloat`. ```julia-console julia> @match 1 begin ::T where T => T end Int64 julia> @match 1 begin ::T where T <: Number => T end Int64 julia> @match 1 begin ::T where T <: AbstractFloat => T end ERROR: matching non-exhaustive, at #= REPL[n]:1 =# ```