fixes
This commit is contained in:
+3
-1
@@ -1,7 +1,9 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
<project version="4">
|
<project version="4">
|
||||||
<component name="UserContentModel">
|
<component name="UserContentModel">
|
||||||
<attachedFolders />
|
<attachedFolders>
|
||||||
|
<Path>../../advanced-pattern-matching-cs-samples</Path>
|
||||||
|
</attachedFolders>
|
||||||
<explicitIncludes />
|
<explicitIncludes />
|
||||||
<explicitExcludes />
|
<explicitExcludes />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
+90
-2
@@ -1,9 +1,12 @@
|
|||||||
// ReSharper disable All
|
// ReSharper disable All
|
||||||
|
|
||||||
|
using System.Text.Json;
|
||||||
|
|
||||||
namespace CS11 {
|
namespace CS11 {
|
||||||
class Program {
|
class Program {
|
||||||
static void Main(string[] args) {
|
static void Main(string[] args) {
|
||||||
int[] numbers = { 1, 3, 42 };
|
int[] numbers = { 1, 3, 42 };
|
||||||
|
// The following match expressions are "slice patterns" - rather unintuitive naming in my eyes, but what can we do.
|
||||||
// Exact match
|
// Exact match
|
||||||
Console.WriteLine($"numbers is [1, 3, 42]: {numbers is [1, 3, 42]}");
|
Console.WriteLine($"numbers is [1, 3, 42]: {numbers is [1, 3, 42]}");
|
||||||
// Must be correct length, so this is false
|
// Must be correct length, so this is false
|
||||||
@@ -20,6 +23,20 @@ namespace CS11 {
|
|||||||
Console.WriteLine($"numbers is [1, 3, >10]: {numbers is [1, 3, > 10]}");
|
Console.WriteLine($"numbers is [1, 3, >10]: {numbers is [1, 3, > 10]}");
|
||||||
// ... and this is false
|
// ... and this is false
|
||||||
Console.WriteLine($"numbers is [1, 3, >100]: {numbers is [1, 3, > 100]}");
|
Console.WriteLine($"numbers is [1, 3, >100]: {numbers is [1, 3, > 100]}");
|
||||||
|
// Other combinations possible, this is true
|
||||||
|
Console.WriteLine($"numbers is [.. , <= 10, >= 10]: {numbers is [.., <= 10, >= 10]}");
|
||||||
|
// The .. operator can be used in the middle as well. It can also match a zero-length part of the list.
|
||||||
|
int[] moreNumbers = [10, 20, 30, 40, 50, 60, 70, 80, 90, 100];
|
||||||
|
Console.WriteLine(
|
||||||
|
$"moreNumbers is [<= 50, <= 50, .., > 50, >= 100]: {moreNumbers is [<= 50, <= 50, .., > 50, >= 100]}");
|
||||||
|
Console.WriteLine(
|
||||||
|
$"numbers is [1, 3, .., 42]: {numbers is [1, 3, .., 42]}");
|
||||||
|
// Note that .. can be used only once. This is invalid.
|
||||||
|
// Console.WriteLine(
|
||||||
|
// $"moreNumbers is [<= 50, <= 50, .., > 50, >= 100]: {moreNumbers is [.., <= 50, <= 50, .., > 50, >= 100]}");
|
||||||
|
|
||||||
|
// And one more strange combination:
|
||||||
|
Console.WriteLine($$"""numbers is [1, .. { Length: 2 }]: {{numbers is [1, .. { Length: 2 }]}}""");
|
||||||
|
|
||||||
// You can split a list into head and tail:
|
// You can split a list into head and tail:
|
||||||
if (numbers is [var x, .. var xs]) {
|
if (numbers is [var x, .. var xs]) {
|
||||||
@@ -33,20 +50,91 @@ namespace CS11 {
|
|||||||
// Talking about spans -- the second new pattern matching feature in
|
// Talking about spans -- the second new pattern matching feature in
|
||||||
// C# 11 is related to spans and strings.
|
// C# 11 is related to spans and strings.
|
||||||
|
|
||||||
string WhatsNext(ReadOnlySpan<char> spanString) => spanString switch {
|
string WhatsNext(ReadOnlySpan<char> spanString) => spanString switch
|
||||||
|
{
|
||||||
"one" => "two",
|
"one" => "two",
|
||||||
"two" => "three",
|
"two" => "three",
|
||||||
_ => "That's it!"
|
_ => "That's it!"
|
||||||
};
|
};
|
||||||
|
|
||||||
Console.WriteLine($"One. Next: '{WhatsNext("one".AsSpan())}'");
|
Console.WriteLine($"One. Next: '{WhatsNext("one".AsSpan())}'");
|
||||||
|
|
||||||
|
//----------------------------------------------
|
||||||
|
//----------------------------------------------
|
||||||
|
// WE'LL GET BACK TO THIS DEMO IN A LITTLE WHILE
|
||||||
|
//----------------------------------------------
|
||||||
|
//----------------------------------------------
|
||||||
|
|
||||||
|
//return;
|
||||||
|
|
||||||
|
#region FP stuff for the second part of the demo
|
||||||
|
|
||||||
|
// Technically, only C# 12 allows collection expressions - we're using them here anyway, for brevity
|
||||||
|
List<double> values = [1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0, 10.0, 11.0];
|
||||||
|
Console.WriteLine($"Downsampled: {JsonSerializer.Serialize(Downsample(values))}");
|
||||||
|
|
||||||
|
List<List<int>> m1 = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
|
||||||
|
Console.WriteLine($"Transpose: {JsonSerializer.Serialize(Transpose(m1))}");
|
||||||
|
Console.WriteLine($"Transpose: {JsonSerializer.Serialize(Transpose_(m1))}");
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
|
|
||||||
// Now we're talking -- note that the use of Span<T> magically solves
|
// Now we're talking -- note that the use of Span<T> magically solves
|
||||||
// a perf problem you would have if you used an Array type here.
|
// a perf problem you would have if you used an Array type here.
|
||||||
static int Sum(Span<int> l) => l switch {
|
static int Sum(Span<int> l) => l switch
|
||||||
|
{
|
||||||
[] => 0,
|
[] => 0,
|
||||||
[var x, .. var xs] => x + Sum(xs)
|
[var x, .. var xs] => x + Sum(xs)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#region FP stuff for the second part of the demo
|
||||||
|
|
||||||
|
// From F#:
|
||||||
|
// let rec downsample : float list -> float list =
|
||||||
|
// function
|
||||||
|
// | [] -> []
|
||||||
|
// | h1::h2::t -> 0.5 * (h1 + h2) :: downsample t
|
||||||
|
// | [_] -> invalid_arg "downsample"
|
||||||
|
|
||||||
|
static List<double> Downsample(List<double> values) => values switch
|
||||||
|
{
|
||||||
|
[var x1, var x2, .. var xs] => new List<double> { (x1 + x2) / 2 }.Concat(Downsample(xs)).ToList(),
|
||||||
|
_ => []
|
||||||
|
};
|
||||||
|
|
||||||
|
// From F#
|
||||||
|
// let rec transpose = function
|
||||||
|
// | (_ :: _) :: _ as xss ->
|
||||||
|
// List.map List.head xss :: transpose (List.map List.tail xss)
|
||||||
|
// | _ -> []
|
||||||
|
|
||||||
|
static List<List<int>> Transpose(List<List<int>> s) => s switch
|
||||||
|
{
|
||||||
|
[[_, .. _], .. _] =>
|
||||||
|
new List<List<int>> { s.Select(x => x.First()).ToList() }
|
||||||
|
.Concat<List<int>>(
|
||||||
|
Transpose(
|
||||||
|
s.Select(x => x.Skip(1).ToList()).ToList()
|
||||||
|
)).ToList(),
|
||||||
|
_ => []
|
||||||
|
};
|
||||||
|
|
||||||
|
// Construction helpers:
|
||||||
|
|
||||||
|
static List<R> Map<T, R>(Func<T, R> f, List<T> l) => l.Select(f).ToList();
|
||||||
|
static T Head<T>(List<T> l) => l[0];
|
||||||
|
static List<T> Tail<T>(List<T> l) => l.Skip(1).ToList();
|
||||||
|
static List<T> Cons<T>(T head, List<T> tail) => new List<T> { head }.Concat(tail).ToList();
|
||||||
|
|
||||||
|
// Much closer now!
|
||||||
|
|
||||||
|
static List<List<int>> Transpose_(List<List<int>> s) => s switch
|
||||||
|
{
|
||||||
|
[[_, .. _], .. _] => Cons(Map(Head, s), Transpose_(Map(Tail, s))),
|
||||||
|
_ => []
|
||||||
|
};
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -34,10 +34,11 @@ namespace CS9 {
|
|||||||
// Positional patterns with "discard" placeholders - note that
|
// Positional patterns with "discard" placeholders - note that
|
||||||
// the element lists must be "complete"!
|
// the element lists must be "complete"!
|
||||||
static OrderValue OrderValueCategory(Order o) =>
|
static OrderValue OrderValueCategory(Order o) =>
|
||||||
o switch {
|
o switch
|
||||||
|
{
|
||||||
// Labels are optional here but can be useful
|
// Labels are optional here but can be useful
|
||||||
// for readability
|
// for readability
|
||||||
(itemCount: < 0, itemPrice: _) => throw new ArgumentException("Positive itemCounts please!"),
|
Order (itemCount: < 0, itemPrice: _) => throw new ArgumentException("Positive itemCounts please!"),
|
||||||
(_, < 0) => throw new ArgumentException("Positive itemPrices please!"),
|
(_, < 0) => throw new ArgumentException("Positive itemPrices please!"),
|
||||||
(>= 100, _) => OrderValue.ValuableDueToHighCount,
|
(>= 100, _) => OrderValue.ValuableDueToHighCount,
|
||||||
(_, >= 1000) => OrderValue.ValuableDueToHighItemPrice,
|
(_, >= 1000) => OrderValue.ValuableDueToHighItemPrice,
|
||||||
@@ -48,7 +49,6 @@ namespace CS9 {
|
|||||||
_ => OrderValue.NotValuable
|
_ => OrderValue.NotValuable
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
static void Main(string[] args) {
|
static void Main(string[] args) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,20 @@
|
|||||||
|
// ReSharper disable InconsistentNaming
|
||||||
|
|
||||||
|
namespace Temp;
|
||||||
|
|
||||||
|
internal class Program {
|
||||||
|
private static void Main(string[] args) {
|
||||||
|
Console.WriteLine("Hello, World!");
|
||||||
|
}
|
||||||
|
|
||||||
|
private (T, U, T, U) BinarySearch<T, U>(Func<T, T, T> Split, Func<T, U> Cmp, (T x, U c_x, T y, U c_y) r) {
|
||||||
|
T m = Split(r.x, r.y);
|
||||||
|
U c_m = Cmp(m);
|
||||||
|
return (r.c_x = c_m, c_m = r.c_y) switch
|
||||||
|
{
|
||||||
|
(true, false) => (m, c_m, r.y, r.c_y),
|
||||||
|
(false, true) => (r.x, r.c_x, m, c_m),
|
||||||
|
_ => throw new Exception("Not found")
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<Project Sdk="Microsoft.NET.Sdk">
|
||||||
|
|
||||||
|
<PropertyGroup>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<TargetFramework>net9.0</TargetFramework>
|
||||||
|
<ImplicitUsings>enable</ImplicitUsings>
|
||||||
|
<Nullable>enable</Nullable>
|
||||||
|
</PropertyGroup>
|
||||||
|
|
||||||
|
</Project>
|
||||||
@@ -9,4 +9,4 @@ fact x | x <= 1 = 1
|
|||||||
fact' :: Int -> Int
|
fact' :: Int -> Int
|
||||||
fact' 0 = 1
|
fact' 0 = 1
|
||||||
fact' 1 = 1
|
fact' 1 = 1
|
||||||
fact' x = x * (fact (x - 1))
|
fact' x = x * (fact' (x - 1))
|
||||||
|
|||||||
@@ -12,3 +12,4 @@ let rec listLength l =
|
|||||||
let rec listLength' = function
|
let rec listLength' = function
|
||||||
| [] -> 0
|
| [] -> 0
|
||||||
| _ :: xs -> 1 + (listLength' xs)
|
| _ :: xs -> 1 + (listLength' xs)
|
||||||
|
|
||||||
|
|||||||
@@ -13,6 +13,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS10", "CS10\CS10.csproj",
|
|||||||
EndProject
|
EndProject
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS11", "CS11\CS11.csproj", "{D1B3E6C4-303A-4A76-B555-4D78E50F8957}"
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "CS11", "CS11\CS11.csproj", "{D1B3E6C4-303A-4A76-B555-4D78E50F8957}"
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Temp", "Temp\Temp.csproj", "{C78DD1B6-35A0-4DAA-85ED-68B06662C523}"
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -42,5 +44,9 @@ Global
|
|||||||
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Release|Any CPU.Build.0 = Release|Any CPU
|
{D1B3E6C4-303A-4A76-B555-4D78E50F8957}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
|
{C78DD1B6-35A0-4DAA-85ED-68B06662C523}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||||
|
{C78DD1B6-35A0-4DAA-85ED-68B06662C523}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||||
|
{C78DD1B6-35A0-4DAA-85ED-68B06662C523}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||||
|
{C78DD1B6-35A0-4DAA-85ED-68B06662C523}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
EndGlobal
|
EndGlobal
|
||||||
|
|||||||
Reference in New Issue
Block a user