Algebraic data types: Difference between revisions

Content added Content deleted
m (syntax highlighting fixup automation)
m (Automated syntax highlighting fixup (second round - minor fixes))
Line 14: Line 14:
=={{header|Bracmat}}==
=={{header|Bracmat}}==


<syntaxhighlight lang=bracmat>( ( balance
<syntaxhighlight lang="bracmat">( ( balance
= a x b y c zd
= a x b y c zd
. !arg
. !arg
Line 63: Line 63:


Test:
Test:
<syntaxhighlight lang=bracmat>( ( it allows for terse code which is easy to read
<syntaxhighlight lang="bracmat">( ( it allows for terse code which is easy to read
, and can represent the algorithm directly
, and can represent the algorithm directly
.
.
Line 74: Line 74:


Output:
Output:
<syntaxhighlight lang=bracmat>(tree=
<syntaxhighlight lang="bracmat">(tree=
B
B
. ( B
. ( B
Line 102: Line 102:
C++ templates have a robust pattern matching facility, with some warts - for example, nested templates cannot be fully specialized, so we must use a dummy template parameter. This implementation uses C++17 deduced template parameters for genericity.
C++ templates have a robust pattern matching facility, with some warts - for example, nested templates cannot be fully specialized, so we must use a dummy template parameter. This implementation uses C++17 deduced template parameters for genericity.


<syntaxhighlight lang=cpp>enum Color { R, B };
<syntaxhighlight lang="cpp">enum Color { R, B };
template<Color, class, auto, class> struct T;
template<Color, class, auto, class> struct T;
struct E;
struct E;
Line 151: Line 151:
Although C++ has structured bindings and pattern matching through function overloading, it is not yet possible to use them together so we must match the structure of the tree being rebalanced separately from decomposing it into its elements. A further issue is that function overloads are not ordered, so to avoid ambiguity we must explicitly reject any (ill-formed) trees that would match more than one case during rebalance.
Although C++ has structured bindings and pattern matching through function overloading, it is not yet possible to use them together so we must match the structure of the tree being rebalanced separately from decomposing it into its elements. A further issue is that function overloads are not ordered, so to avoid ambiguity we must explicitly reject any (ill-formed) trees that would match more than one case during rebalance.


<syntaxhighlight lang=cpp>#include <memory>
<syntaxhighlight lang="cpp">#include <memory>
#include <variant>
#include <variant>


Line 258: Line 258:
Translation of several
Translation of several
{{works with|C sharp|8}}
{{works with|C sharp|8}}
<syntaxhighlight lang=csharp>using System;
<syntaxhighlight lang="csharp">using System;


class Tree
class Tree
Line 356: Line 356:
{{libheader|toadstool}}
{{libheader|toadstool}}


<syntaxhighlight lang=lisp>(mapc #'use-package '(#:toadstool #:toadstool-system))
<syntaxhighlight lang="lisp">(mapc #'use-package '(#:toadstool #:toadstool-system))
(defstruct (red-black-tree (:constructor tree (color left val right)))
(defstruct (red-black-tree (:constructor tree (color left val right)))
color left val right)
color left val right)
Line 441: Line 441:


=={{header|EchoLisp}}==
=={{header|EchoLisp}}==
<syntaxhighlight lang=scheme>
<syntaxhighlight lang="scheme">
;; code adapted from Racket and Common Lisp
;; code adapted from Racket and Common Lisp
;; Illustrates matching on structures
;; Illustrates matching on structures
Line 471: Line 471:
</syntaxhighlight>
</syntaxhighlight>
{{out}}
{{out}}
<syntaxhighlight lang=scheme>
<syntaxhighlight lang="scheme">
(define (t-show n (depth 0))
(define (t-show n (depth 0))
(when (!eq? 'empty n)
(when (!eq? 'empty n)
Line 515: Line 515:
{{trans|Erlang}}
{{trans|Erlang}}
But, it changed an API into the Elixir style.
But, it changed an API into the Elixir style.
<syntaxhighlight lang=elixir>defmodule RBtree do
<syntaxhighlight lang="elixir">defmodule RBtree do
def find(nil, _), do: :not_found
def find(nil, _), do: :not_found
def find({ key, value, _, _, _ }, key), do: { :found, { key, value } }
def find({ key, value, _, _, _ }, key), do: { :found, { key, value } }
Line 580: Line 580:
The <code>pcase</code> macro was added in Emacs 24.1. It's auto-loaded, so there's no need to add <code>(require 'pcase)</code> to your code.
The <code>pcase</code> macro was added in Emacs 24.1. It's auto-loaded, so there's no need to add <code>(require 'pcase)</code> to your code.


<syntaxhighlight lang=lisp>(defun rbt-balance (tree)
<syntaxhighlight lang="lisp">(defun rbt-balance (tree)
(pcase tree
(pcase tree
(`(B (R (R ,a ,x ,b) ,y ,c) ,z ,d) `(R (B ,a ,x ,b) ,y (B ,c ,z ,d)))
(`(B (R (R ,a ,x ,b) ,y ,c) ,z ,d) `(R (B ,a ,x ,b) ,y (B ,c ,z ,d)))
Line 639: Line 639:


The code used here is extracted from [https://gist.github.com/mjn/2648040 Mark Northcott's GitHubGist].
The code used here is extracted from [https://gist.github.com/mjn/2648040 Mark Northcott's GitHubGist].
<syntaxhighlight lang=erlang>
<syntaxhighlight lang="erlang">
-module(rbtree).
-module(rbtree).
-export([insert/3, find/2]).
-export([insert/3, find/2]).
Line 714: Line 714:


=={{header|F_Sharp|F#}}==
=={{header|F_Sharp|F#}}==
<syntaxhighlight lang=fsharp>
<syntaxhighlight lang="fsharp">
// Pattern Matching. Nigel Galloway: January 15th., 2021
// Pattern Matching. Nigel Galloway: January 15th., 2021
type colour= |Red |Black
type colour= |Red |Black
Line 734: Line 734:


However, pattern matching on interfaces (via the type switch statement and type assertions) is limited to matching the implementing type and so the balance() method is not very pleasant.
However, pattern matching on interfaces (via the type switch statement and type assertions) is limited to matching the implementing type and so the balance() method is not very pleasant.
<syntaxhighlight lang=go>package main
<syntaxhighlight lang="go">package main


import "fmt"
import "fmt"
Line 860: Line 860:
=={{header|Haskell}}==
=={{header|Haskell}}==


<syntaxhighlight lang=haskell>data Color = R | B
<syntaxhighlight lang="haskell">data Color = R | B
data Tree a = E | T Color (Tree a) a (Tree a)
data Tree a = E | T Color (Tree a) a (Tree a)


Line 886: Line 886:
The following code represents a best effort translation of the current Haskell implementation of this task:
The following code represents a best effort translation of the current Haskell implementation of this task:


<syntaxhighlight lang=J>insert=:{{
<syntaxhighlight lang="j">insert=:{{
'R';'';y;a:
'R';'';y;a:
:
:
Line 928: Line 928:
Example use:
Example use:


<syntaxhighlight lang=J> 3 insert 2 insert 5
<syntaxhighlight lang="j"> 3 insert 2 insert 5
┌─┬───────┬─┬───────┐
┌─┬───────┬─┬───────┐
│R│┌─┬┬─┬┐│3│┌─┬┬─┬┐│
│R│┌─┬┬─┬┐│3│┌─┬┬─┬┐│
Line 937: Line 937:
Note that by convention we treat the root node as black. This approach always labels it with 'R' which we ignore. However, if we wish to validate these trees, we must account for the discrepancy.
Note that by convention we treat the root node as black. This approach always labels it with 'R' which we ignore. However, if we wish to validate these trees, we must account for the discrepancy.


<syntaxhighlight lang=J>NB. always treat root of tree as black
<syntaxhighlight lang="j">NB. always treat root of tree as black
validate=: {{
validate=: {{
if. 0=#y do. 1 return. end.
if. 0=#y do. 1 return. end.
Line 960: Line 960:
For example:
For example:


<syntaxhighlight lang=J> ?.~20
<syntaxhighlight lang="j"> ?.~20
14 18 12 16 5 1 3 0 6 13 9 8 15 17 2 10 7 4 19 11
14 18 12 16 5 1 3 0 6 13 9 8 15 17 2 10 7 4 19 11
insert/?.~20
insert/?.~20
Line 990: Line 990:


'''bindings.jq'''
'''bindings.jq'''
<syntaxhighlight lang=jq># bindings($x) attempts to match . and $x structurally on the
<syntaxhighlight lang="jq"># bindings($x) attempts to match . and $x structurally on the
# assumption that . is free of JSON objects, and that any objects in
# assumption that . is free of JSON objects, and that any objects in
# $x will have distinct, singleton keys that are to be interpreted as
# $x will have distinct, singleton keys that are to be interpreted as
Line 1,020: Line 1,020:


'''pattern-matching.jq'''
'''pattern-matching.jq'''
<syntaxhighlight lang=jq>include "bindings" {search: "."};
<syntaxhighlight lang="jq">include "bindings" {search: "."};


def E: []; # the empty node
def E: []; # the empty node
Line 1,064: Line 1,064:
{{out}}
{{out}}
For brevity and perhaps visual appeal, the output from jq has been trimmed as per the following invocation:
For brevity and perhaps visual appeal, the output from jq has been trimmed as per the following invocation:
<syntaxhighlight lang=sh>jq -n -f pattern-matching.jq | grep -v '[][]' | tr -d ',"'</syntaxhighlight>
<syntaxhighlight lang="sh">jq -n -f pattern-matching.jq | grep -v '[][]' | tr -d ',"'</syntaxhighlight>
<pre>
<pre>
Line 1,101: Line 1,101:
=={{header|Julia}}==
=={{header|Julia}}==
Julia's multiple dispatch model is based on the types of a function's arguments, but does not look deeper into the function's array arguments for the types of their contents. Therefore we do multi-dispatch on the balance function but then use an if statement within the multiply dispatched functions to further match based on argument vector contents.
Julia's multiple dispatch model is based on the types of a function's arguments, but does not look deeper into the function's array arguments for the types of their contents. Therefore we do multi-dispatch on the balance function but then use an if statement within the multiply dispatched functions to further match based on argument vector contents.
<syntaxhighlight lang=julia>import Base.length
<syntaxhighlight lang="julia">import Base.length


abstract type AbstractColoredNode end
abstract type AbstractColoredNode end
Line 1,179: Line 1,179:
Whilst Kotlin supports algebraic data types (via 'sealed classes') and destructuring of data classes, pattern matching on them (via the 'when' expression) is currently limited to matching the type. Consequently the balance() function is not very pretty!
Whilst Kotlin supports algebraic data types (via 'sealed classes') and destructuring of data classes, pattern matching on them (via the 'when' expression) is currently limited to matching the type. Consequently the balance() function is not very pretty!
<syntaxhighlight lang=scala>// version 1.1.51
<syntaxhighlight lang="scala">// version 1.1.51


import Color.*
import Color.*
Line 1,270: Line 1,270:
=={{header|Nim}}==
=={{header|Nim}}==
{{libheader|fusion/matching}}
{{libheader|fusion/matching}}
<syntaxhighlight lang=nim>import fusion/matching
<syntaxhighlight lang="nim">import fusion/matching
{.experimental: "caseStmtMacros".}
{.experimental: "caseStmtMacros".}


Line 1,317: Line 1,317:


=={{header|OCaml}}==
=={{header|OCaml}}==
<syntaxhighlight lang=ocaml>
<syntaxhighlight lang="ocaml">
type color = R | B
type color = R | B
type 'a tree = E | T of color * 'a tree * 'a * 'a tree
type 'a tree = E | T of color * 'a tree * 'a * 'a tree
Line 1,350: Line 1,350:
To match multiple variables at once, we create temporary tuples with "#".
To match multiple variables at once, we create temporary tuples with "#".


<syntaxhighlight lang=oz>fun {Balance Col A X B}
<syntaxhighlight lang="oz">fun {Balance Col A X B}
case Col#A#X#B
case Col#A#X#B
of b#t(r t(r A X B) Y C )#Z#D then t(r t(b A X B) Y t(b C Z D))
of b#t(r t(r A X B) Y C )#Z#D then t(r t(b A X B) Y t(b C Z D))
Line 1,386: Line 1,386:
Each of the single letter variables declared right after $balanced, match an instance of $balanced, and if they succeed, store the result into the %+ hash.
Each of the single letter variables declared right after $balanced, match an instance of $balanced, and if they succeed, store the result into the %+ hash.


<syntaxhighlight lang=perl>#!perl
<syntaxhighlight lang="perl">#!perl
use 5.010;
use 5.010;
use strict;
use strict;
Line 1,468: Line 1,468:
There is no formal support for this sort of thing in Phix, but that's not to say that whipping
There is no formal support for this sort of thing in Phix, but that's not to say that whipping
something up is likely to be particularly difficult, so let's give it a whirl.
something up is likely to be particularly difficult, so let's give it a whirl.
<!--<syntaxhighlight lang=Phix>(phixonline)-->
<!--<syntaxhighlight lang="phix">(phixonline)-->
<span style="color: #000080;font-style:italic;">--
<span style="color: #000080;font-style:italic;">--
-- demo\rosetta\Pattern_matching.exw
-- demo\rosetta\Pattern_matching.exw
Line 1,612: Line 1,612:
=={{header|Picat}}==
=={{header|Picat}}==
{{trans|Prolog}}
{{trans|Prolog}}
<syntaxhighlight lang=Picat>main =>
<syntaxhighlight lang="picat">main =>
T = e,
T = e,
foreach (X in 1..10)
foreach (X in 1..10)
Line 1,670: Line 1,670:
=={{header|PicoLisp}}==
=={{header|PicoLisp}}==
{{trans|Prolog}}
{{trans|Prolog}}
<syntaxhighlight lang=PicoLisp>(be color (R))
<syntaxhighlight lang="picolisp">(be color (R))
(be color (B))
(be color (B))


Line 1,706: Line 1,706:
(ins @X @S (T @ @A @Y @B)) )</syntaxhighlight>
(ins @X @S (T @ @A @Y @B)) )</syntaxhighlight>
Test:
Test:
<syntaxhighlight lang=PicoLisp>: (? (insert 2 E @A) (insert 1 @A @B) (insert 3 @B @C))
<syntaxhighlight lang="picolisp">: (? (insert 2 E @A) (insert 1 @A @B) (insert 3 @B @C))
@A=(T B E 2 E) @B=(T B (T R E 1 E) 2 E) @C=(T B (T R E 1 E) 2 (T R E 3 E))
@A=(T B E 2 E) @B=(T B (T R E 1 E) 2 E) @C=(T B (T R E 1 E) 2 (T R E 3 E))
-> NIL</syntaxhighlight>
-> NIL</syntaxhighlight>
Line 1,739: Line 1,739:
Structural pattern matching was added to Python in version 3.10.
Structural pattern matching was added to Python in version 3.10.


<syntaxhighlight lang=python>from __future__ import annotations
<syntaxhighlight lang="python">from __future__ import annotations
from enum import Enum
from enum import Enum
from typing import NamedTuple
from typing import NamedTuple
Line 1,871: Line 1,871:
{{trans|OCaml}}
{{trans|OCaml}}


<syntaxhighlight lang=racket>
<syntaxhighlight lang="racket">
#lang racket
#lang racket


Line 1,929: Line 1,929:
{{works with|rakudo|2016.11}}
{{works with|rakudo|2016.11}}
Raku doesn't have algebraic data types (yet), but it does have pretty good pattern matching in multi signatures.
Raku doesn't have algebraic data types (yet), but it does have pretty good pattern matching in multi signatures.
<syntaxhighlight lang=perl6>enum RedBlack <R B>;
<syntaxhighlight lang="raku" line>enum RedBlack <R B>;


multi balance(B,[R,[R,$a,$x,$b],$y,$c],$z,$d) { [R,[B,$a,$x,$b],$y,[B,$c,$z,$d]] }
multi balance(B,[R,[R,$a,$x,$b],$y,$c],$z,$d) { [R,[B,$a,$x,$b],$y,[B,$c,$z,$d]] }
Line 1,965: Line 1,965:


An abstract pattern is recursively defined and may contain, among others, the following elements: Literal, VariableDeclaration, MultiVariable, Variable, List, Set, Tuple, Node, Descendant, Labelled, TypedLabelled, TypeConstrained. More explanation can be found in the [http://http://tutor.rascal-mpl.org/Courses/Rascal/Rascal.html#/Courses/Rascal/Patterns/Abstract/Abstract.html Documentation]. Some examples:
An abstract pattern is recursively defined and may contain, among others, the following elements: Literal, VariableDeclaration, MultiVariable, Variable, List, Set, Tuple, Node, Descendant, Labelled, TypedLabelled, TypeConstrained. More explanation can be found in the [http://http://tutor.rascal-mpl.org/Courses/Rascal/Rascal.html#/Courses/Rascal/Patterns/Abstract/Abstract.html Documentation]. Some examples:
<syntaxhighlight lang=rascal>
<syntaxhighlight lang="rascal">
// Literal
// Literal
rascal>123 := 123
rascal>123 := 123
Line 2,037: Line 2,037:


A concrete pattern is a quoted concrete syntax fragment that may contain variables. The syntax that is used to parse the concrete pattern may come from any module that has been imported in the module in which the concrete pattern occurs. Some examples of concrete patterns:
A concrete pattern is a quoted concrete syntax fragment that may contain variables. The syntax that is used to parse the concrete pattern may come from any module that has been imported in the module in which the concrete pattern occurs. Some examples of concrete patterns:
<syntaxhighlight lang=rascal>// Quoted pattern
<syntaxhighlight lang="rascal">// Quoted pattern
` Token1 Token2 ... Tokenn `
` Token1 Token2 ... Tokenn `
// A typed quoted pattern
// A typed quoted pattern
Line 2,052: Line 2,052:
There are two variants of the PatternsWitchAction. When the subject matches Pattern, the expression Exp is evaluated and the subject is replaced with the result. Secondly, when the subject matches Pattern, the (block of) Statement(s) is executed. See below for some ColoredTree examples:
There are two variants of the PatternsWitchAction. When the subject matches Pattern, the expression Exp is evaluated and the subject is replaced with the result. Secondly, when the subject matches Pattern, the (block of) Statement(s) is executed. See below for some ColoredTree examples:


<syntaxhighlight lang=rascal>// Define ColoredTrees with red and black nodes and integer leaves
<syntaxhighlight lang="rascal">// Define ColoredTrees with red and black nodes and integer leaves
data ColoredTree = leaf(int N)
data ColoredTree = leaf(int N)
| red(ColoredTree left, ColoredTree right)
| red(ColoredTree left, ColoredTree right)
Line 2,097: Line 2,097:
Regular expressions are noated between two slashes. Most normal regular expressions patterns are available, such as ., \n, \d, etc. Additionally, flags can be used to create case intensiveness.
Regular expressions are noated between two slashes. Most normal regular expressions patterns are available, such as ., \n, \d, etc. Additionally, flags can be used to create case intensiveness.


<syntaxhighlight lang=rascal>rascal>/XX/i := "some xx";
<syntaxhighlight lang="rascal">rascal>/XX/i := "some xx";
bool: true
bool: true
rascal>/a.c/ := "abc";
rascal>/a.c/ := "abc";
Line 2,105: Line 2,105:
The nodes used for this example are taken from the Wikipedia example at: &nbsp;
The nodes used for this example are taken from the Wikipedia example at: &nbsp;
[[https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#/media/File:Red-black_tree_example.svg red black tree, an example]]
[[https://en.wikipedia.org/wiki/Red%E2%80%93black_tree#/media/File:Red-black_tree_example.svg red black tree, an example]]
<syntaxhighlight lang=rexx>/*REXX pgm builds a red/black tree (with verification & validation), balanced as needed.*/
<syntaxhighlight lang="rexx">/*REXX pgm builds a red/black tree (with verification & validation), balanced as needed.*/
parse arg nodes '/' insert /*obtain optional arguments from the CL*/
parse arg nodes '/' insert /*obtain optional arguments from the CL*/
if nodes='' then nodes = 13.8.17 8.1.11 17.15.25 1.6 25.22.27 /*default nodes. */
if nodes='' then nodes = 13.8.17 8.1.11 17.15.25 1.6 25.22.27 /*default nodes. */
Line 2,156: Line 2,156:
{{trans|Haskell}}
{{trans|Haskell}}
This would be a horribly inefficient way to implement a Red-Black Tree in Rust as nodes are being allocated and deallocated constantly, but it does show off Rust's pattern matching.
This would be a horribly inefficient way to implement a Red-Black Tree in Rust as nodes are being allocated and deallocated constantly, but it does show off Rust's pattern matching.
<syntaxhighlight lang=rust>#![feature(box_patterns, box_syntax)]
<syntaxhighlight lang="rust">#![feature(box_patterns, box_syntax)]
use self::Color::*;
use self::Color::*;
use std::cmp::Ordering::*;
use std::cmp::Ordering::*;
Line 2,233: Line 2,233:
of that object.
of that object.


<syntaxhighlight lang=scala>class RedBlackTree[A](implicit ord: Ordering[A]) {
<syntaxhighlight lang="scala">class RedBlackTree[A](implicit ord: Ordering[A]) {
sealed abstract class Color
sealed abstract class Color
case object R extends Color
case object R extends Color
Line 2,282: Line 2,282:


=={{header|Standard ML}}==
=={{header|Standard ML}}==
<syntaxhighlight lang=sml>
<syntaxhighlight lang="sml">
datatype color = R | B
datatype color = R | B
datatype 'a tree = E | T of color * 'a tree * 'a * 'a tree
datatype 'a tree = E | T of color * 'a tree * 'a * 'a tree
Line 2,311: Line 2,311:
=={{header|Swift}}==
=={{header|Swift}}==
{{works with|Swift|2+}}
{{works with|Swift|2+}}
<syntaxhighlight lang=swift>enum Color { case R, B }
<syntaxhighlight lang="swift">enum Color { case R, B }
enum Tree<A> {
enum Tree<A> {
case E
case E
Line 2,353: Line 2,353:


Tailspin doesn't have type names, so here using a tag. Neither does it have destructuring (which seems to be posited in the problem statement). Arguably, pattern matching in Tailspin is more readable while still as concise.
Tailspin doesn't have type names, so here using a tag. Neither does it have destructuring (which seems to be posited in the problem statement). Arguably, pattern matching in Tailspin is more readable while still as concise.
<syntaxhighlight lang=tailspin>
<syntaxhighlight lang="tailspin">
processor RedBlackTree
processor RedBlackTree
data node <{VOID}|{colour: <='black'|='red'>, left: <node>, right: <node>, value: <> VOID}> local
data node <{VOID}|{colour: <='black'|='red'>, left: <node>, right: <node>, value: <> VOID}> local
Line 2,411: Line 2,411:


Tcl doesn't have algebraic types built-in, but they can be simulated using tagged lists, and a custom pattern matching control structure can be built:
Tcl doesn't have algebraic types built-in, but they can be simulated using tagged lists, and a custom pattern matching control structure can be built:
<syntaxhighlight lang=tcl># From http://wiki.tcl.tk/9547
<syntaxhighlight lang="tcl"># From http://wiki.tcl.tk/9547
package require Tcl 8.5
package require Tcl 8.5
package provide datatype 0.1
package provide datatype 0.1
Line 2,484: Line 2,484:
We can then code our solution similar to Haskell:
We can then code our solution similar to Haskell:


<syntaxhighlight lang=tcl>datatype define Color = R | B
<syntaxhighlight lang="tcl">datatype define Color = R | B
datatype define Tree = E | T color left val right
datatype define Tree = E | T color left val right


Line 2,518: Line 2,518:
{{trans|Go}}
{{trans|Go}}
Wren doesn't have either algebraic data types or pattern matching though, despite that, the ''T.balance()'' method looks better than I thought it would :)
Wren doesn't have either algebraic data types or pattern matching though, despite that, the ''T.balance()'' method looks better than I thought it would :)
<syntaxhighlight lang=ecmascript>var R = "R"
<syntaxhighlight lang="ecmascript">var R = "R"
var B = "B"
var B = "B"