init concurrency
This commit is contained in:
commit
b73cb00e1f
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,53 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{7DD5E681-8526-470B-8550-8F28A657269D}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>Appendix.A</RootNamespace>
|
||||||
|
<AssemblyName>Appendix.A</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Listings.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,151 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Appendix.A
|
||||||
|
{
|
||||||
|
public static class Listings
|
||||||
|
{
|
||||||
|
public static void HigherOrderFunctios()
|
||||||
|
{
|
||||||
|
Func<int, double> fCos = n => Math.Cos((double)n);
|
||||||
|
|
||||||
|
double x = fCos(5);
|
||||||
|
|
||||||
|
IEnumerable<double> values = Enumerable.Range(1, 10).Select(fCos);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HigherOrderFunctiosAndLambda(string path)
|
||||||
|
{
|
||||||
|
string text;
|
||||||
|
using (var stream = new StreamReader(path))
|
||||||
|
{
|
||||||
|
text = stream.ReadToEnd();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static R Using<T, R>(this T item, Func<T, R> func) where T : IDisposable
|
||||||
|
{
|
||||||
|
using (item)
|
||||||
|
return func(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void HigherOrderFunctiosAndLambdaReusableCode(string path)
|
||||||
|
{
|
||||||
|
string text = new StreamReader(path).Using(stream => stream.ReadToEnd());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void LambdaExpressionWithSameBehavior()
|
||||||
|
{
|
||||||
|
Func<int, int, int> add1 = delegate (int x, int y) { return x + y; };
|
||||||
|
Func<int, int, int> add2 = (int x, int y) => { return x + y; };
|
||||||
|
Func<int, int, int> add3 = (x, y) => x + y;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CurringFunctions()
|
||||||
|
{
|
||||||
|
Func<int, int, int> add = (x, y) => x + y;
|
||||||
|
Func<int, Func<int, int>> curriedAdd = x => y => x + y;
|
||||||
|
|
||||||
|
Func<int, int> increament = curriedAdd(1);
|
||||||
|
|
||||||
|
int a = increament(30);
|
||||||
|
int b = increament(41);
|
||||||
|
|
||||||
|
|
||||||
|
Func<int, int> add30 = curriedAdd(30);
|
||||||
|
int c = add30(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Func<A, Func<B, R>> Curry<A, B, R>(this Func<A, B, R> function)
|
||||||
|
{
|
||||||
|
return a => b => function(a, b);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void CurryingHelperExtenion()
|
||||||
|
{
|
||||||
|
Func<int, int, int> add = (x, y) => x + y;
|
||||||
|
Func<int, Func<int, int>> curriedAdd = add.Curry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Func<A, B, R> Uncurry<A, B, R>(Func<A, Func<B, R>> function)
|
||||||
|
=> (x, y) => function(x)(y);
|
||||||
|
|
||||||
|
static Func<B, R> Partial<A, B, R>(this Func<A, B, R> function, A argument)
|
||||||
|
=> argument2 => function(argument, argument2);
|
||||||
|
|
||||||
|
|
||||||
|
public static void PartiallyAppliedFunctions()
|
||||||
|
{
|
||||||
|
Func<int, int, int> add = (x, y) => x + y;
|
||||||
|
|
||||||
|
Func<int, int, int> max = Math.Max;
|
||||||
|
Func<int, int> max5 = max.Partial(5);
|
||||||
|
|
||||||
|
int a = max5(8);
|
||||||
|
int b = max5(2);
|
||||||
|
int c = max5(12);
|
||||||
|
}
|
||||||
|
|
||||||
|
static string ReadText(string filePath) => File.ReadAllText(filePath);
|
||||||
|
|
||||||
|
public static void PartiallyAppliedFunctionExample()
|
||||||
|
{
|
||||||
|
string filePath = "TextFile.txt";
|
||||||
|
Func<string> readText = () => ReadText(filePath);
|
||||||
|
|
||||||
|
string text = readText.Retry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void PartiallyAppliedExtensionMethodExample(string filePath)
|
||||||
|
{
|
||||||
|
Func<string, string> readText = (path) => ReadText(path);
|
||||||
|
|
||||||
|
// string text = readText.Retry(); Error!!
|
||||||
|
// string text = readText(filePath).Retry(); Error!!
|
||||||
|
|
||||||
|
string text = readText.Partial("TextFile.txt").Retry();
|
||||||
|
|
||||||
|
Func<string, Func<string>> curriedReadText = readText.Curry();
|
||||||
|
|
||||||
|
text = curriedReadText("TextFile.txt").Retry();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Func<R> Partial<T, R>(this Func<T, R> function, T arg)
|
||||||
|
{
|
||||||
|
return () => function(arg);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Func<T, Func<R>> Curry<T, R>(this Func<T, R> function)
|
||||||
|
{
|
||||||
|
return arg => () => function(arg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class PartiallyAppliedRetryFunction
|
||||||
|
{
|
||||||
|
public static T Retry<T>(this Func<T> function)
|
||||||
|
{
|
||||||
|
int retry = 0;
|
||||||
|
T result = default(T);
|
||||||
|
bool success = false;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
result = function();
|
||||||
|
success = true;
|
||||||
|
}
|
||||||
|
catch
|
||||||
|
{
|
||||||
|
retry++;
|
||||||
|
}
|
||||||
|
} while (!success && retry < 3);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,15 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace Appendix.A
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("Appendix.A")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("Appendix.A")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("7dd5e681-8526-470b-8550-8f28a657269d")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,41 @@
|
||||||
|
namespace FSharp.Tutorial.AssemblyInfo
|
||||||
|
|
||||||
|
open System.Reflection
|
||||||
|
open System.Runtime.CompilerServices
|
||||||
|
open System.Runtime.InteropServices
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[<assembly: AssemblyTitle("FSharp.Tutorial")>]
|
||||||
|
[<assembly: AssemblyDescription("")>]
|
||||||
|
[<assembly: AssemblyConfiguration("")>]
|
||||||
|
[<assembly: AssemblyCompany("")>]
|
||||||
|
[<assembly: AssemblyProduct("FSharp.Tutorial")>]
|
||||||
|
[<assembly: AssemblyCopyright("Copyright © 2018")>]
|
||||||
|
[<assembly: AssemblyTrademark("")>]
|
||||||
|
[<assembly: AssemblyCulture("")>]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[<assembly: ComVisible(false)>]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[<assembly: Guid("41f033c7-f85b-4bd5-af28-66810b0e1110")>]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [<assembly: AssemblyVersion("1.0.*")>]
|
||||||
|
[<assembly: AssemblyVersion("1.0.0.0")>]
|
||||||
|
[<assembly: AssemblyFileVersion("1.0.0.0")>]
|
||||||
|
|
||||||
|
do
|
||||||
|
()
|
|
@ -0,0 +1,73 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>41f033c7-f85b-4bd5-af28-66810b0e1110</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>FSharp.Tutorial</RootNamespace>
|
||||||
|
<AssemblyName>FSharp.Tutorial</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<UseStandardResourceNames>true</UseStandardResourceNames>
|
||||||
|
<Name>FSharp.Tutorial</Name>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\$(Configuration)\$(AssemblyName).XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\$(Configuration)\$(AssemblyName).XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(FSharpTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets') ">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="AssemblyInfo.fs" />
|
||||||
|
<Compile Include="Program.fs" />
|
||||||
|
<None Include="App.config" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.ValueTuple">
|
||||||
|
<HintPath>..\..\packages\System.ValueTuple.4.4.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,295 @@
|
||||||
|
open System
|
||||||
|
// let binding
|
||||||
|
module binding =
|
||||||
|
let myInt = 42
|
||||||
|
let myFloat = 3.14
|
||||||
|
let myString = "hello functional programming"
|
||||||
|
let myFunction = fun number -> number * number
|
||||||
|
|
||||||
|
// Create mutable types – mutable and ref
|
||||||
|
let mutable myNumber = 42
|
||||||
|
myNumber <- 51
|
||||||
|
|
||||||
|
let myRefVar = ref 42
|
||||||
|
myRefVar := 53
|
||||||
|
printfn "%d" !myRefVar
|
||||||
|
|
||||||
|
// Functions as first class types
|
||||||
|
module FunctionFirstClass =
|
||||||
|
let square x = x * x
|
||||||
|
let plusOne x = x + 1
|
||||||
|
let isEven x = x % 2 = 0
|
||||||
|
|
||||||
|
// Composition - Pipe and Composition operators
|
||||||
|
let inline (|>) x f = f x
|
||||||
|
let inline (>>) f g x = g(f x)
|
||||||
|
|
||||||
|
let squarePlusOne x = x |> square |> plusOne
|
||||||
|
let plusOneIsEven = plusOne >> isEven
|
||||||
|
|
||||||
|
// Delegates
|
||||||
|
module Delegates =
|
||||||
|
// type delegate typename = delegate of typeA -> typeB
|
||||||
|
|
||||||
|
type MyDelegate = delegate of (int * int) -> int
|
||||||
|
let add (a, b) = a + b
|
||||||
|
let addDelegate = MyDelegate(add)
|
||||||
|
let result = addDelegate.Invoke(33, 9)
|
||||||
|
|
||||||
|
// Comments
|
||||||
|
(* This is block comment *)
|
||||||
|
// Single line comments use a double forward slash
|
||||||
|
/// This comment can be used to generate documentation.
|
||||||
|
|
||||||
|
// Special String definition
|
||||||
|
module Strings =
|
||||||
|
let verbatimHtml = @"<input type=\""submit\"" value=\""Submit\"">"
|
||||||
|
let tripleHTML = """<input type="submit" value="Submit">"""
|
||||||
|
|
||||||
|
// Tuple
|
||||||
|
module Tuple =
|
||||||
|
let tuple = (1, "Hello")
|
||||||
|
let tripleTuple = ("one", "two", "three")
|
||||||
|
|
||||||
|
let tupleStruct = struct (1, "Hello")
|
||||||
|
|
||||||
|
let (a, b) = tuple
|
||||||
|
let swap (a, b) = (b, a)
|
||||||
|
|
||||||
|
let one = fst tuple
|
||||||
|
let hello = snd tuple
|
||||||
|
|
||||||
|
// Record-Types
|
||||||
|
module RecordTypes =
|
||||||
|
type Person = { FirstName : string; LastName : string; Age : int }
|
||||||
|
let fred = { FirstName = "Fred"; LastName = "Flintstone"; Age = 42 }
|
||||||
|
|
||||||
|
type Person with
|
||||||
|
member this.FullName = sprintf "%s %s" this.FirstName this.LastName
|
||||||
|
|
||||||
|
let olderFred = { fred with Age = fred.Age + 1 }
|
||||||
|
|
||||||
|
[<Struct>]
|
||||||
|
type Person_Struct = { FirstName : string; LastName : string; Age : int }
|
||||||
|
|
||||||
|
// Discriminated Unions
|
||||||
|
module Discriminated_Unions =
|
||||||
|
type Suit = Hearts | Clubs | Diamonds | Spades
|
||||||
|
|
||||||
|
type Rank =
|
||||||
|
| Value of int
|
||||||
|
| Ace
|
||||||
|
| King
|
||||||
|
| Queen
|
||||||
|
| Jack
|
||||||
|
static member GetAllRanks() =
|
||||||
|
[ yield Ace
|
||||||
|
for i in 2 .. 10 do yield Value i
|
||||||
|
yield Jack
|
||||||
|
yield Queen
|
||||||
|
yield King ]
|
||||||
|
|
||||||
|
type Card = { Suit:Suit; Rank:Rank }
|
||||||
|
|
||||||
|
let fullDeck =
|
||||||
|
[ for suit in [ Hearts; Diamonds; Clubs; Spades] do
|
||||||
|
for rank in Rank.GetAllRanks() do
|
||||||
|
yield { Suit=suit; Rank=rank } ]
|
||||||
|
|
||||||
|
// Pattern matching
|
||||||
|
module Pattern_matching =
|
||||||
|
let fizzBuzz n =
|
||||||
|
let divisibleBy m = n % m = 0
|
||||||
|
match divisibleBy 3,divisibleBy 5 with
|
||||||
|
| true, false -> "Fizz"
|
||||||
|
| false, true -> "Buzz"
|
||||||
|
| true, true -> "FizzBuzz"
|
||||||
|
| false, false -> sprintf "%d" n
|
||||||
|
|
||||||
|
let fizzBuzz' n =
|
||||||
|
match n with
|
||||||
|
| _ when (n % 15) = 0 -> "FizzBuzz"
|
||||||
|
| _ when (n % 3) = 0 -> "Fizz"
|
||||||
|
| _ when (n % 5) = 0 -> "Buzz"
|
||||||
|
| _ -> sprintf "%d" n
|
||||||
|
|
||||||
|
[1..20] |> List.iter(fun s -> printfn "%s" (fizzBuzz' s))
|
||||||
|
|
||||||
|
// Active patterns
|
||||||
|
let (|DivisibleBy|_|) divideBy n =
|
||||||
|
if n % divideBy = 0 then Some DivisibleBy else None
|
||||||
|
|
||||||
|
|
||||||
|
let fizzBuzz'' n =
|
||||||
|
match n with
|
||||||
|
| DivisibleBy 3 & DivisibleBy 5 -> "FizzBuzz"
|
||||||
|
| DivisibleBy 3 -> "Fizz"
|
||||||
|
| DivisibleBy 5 -> "Buzz"
|
||||||
|
| _ -> sprintf "%d" n
|
||||||
|
|
||||||
|
[1..20] |> List.iter(fun s -> printfn "%s" (fizzBuzz'' s))
|
||||||
|
|
||||||
|
let (|Fizz|Buzz|FizzBuzz|Val|) n =
|
||||||
|
match n % 3, n % 5 with
|
||||||
|
| 0, 0 -> FizzBuzz
|
||||||
|
| 0, _ -> Fizz
|
||||||
|
| _, 0 -> Buzz
|
||||||
|
| _ -> Val n
|
||||||
|
|
||||||
|
// Arrays
|
||||||
|
module Arrays =
|
||||||
|
let emptyArray1 = Array.empty
|
||||||
|
let emptyArray2 = [| |]
|
||||||
|
let arrayOfFiveElements = [| 1; 2; 3; 4; 5 |]
|
||||||
|
let arrayFromTwoToTen= [| 2..10 |]
|
||||||
|
let appendTwoArrays = emptyArray1 |> Array.append arrayFromTwoToTen
|
||||||
|
let evenNumbers = arrayFromTwoToTen |> Array.filter(fun n -> n % 2 = 0)
|
||||||
|
let squareNumbers = evenNumbers |> Array.map(fun n -> n * n)
|
||||||
|
|
||||||
|
let arr = Array.init 10 (fun i -> i * i)
|
||||||
|
arr.[1] <- 42
|
||||||
|
arr.[7] <- 91
|
||||||
|
|
||||||
|
let arrOfBytes = Array.create 42 0uy
|
||||||
|
let arrOfSquare = Array.init 42 (fun i -> i * i)
|
||||||
|
let arrOfIntegers = Array.zeroCreate<int> 42
|
||||||
|
|
||||||
|
// Sequences
|
||||||
|
module Sequences =
|
||||||
|
let emptySeq = Seq.empty
|
||||||
|
let seqFromTwoToFive = seq { yield 2; yield 3; yield 4; yield 5 }
|
||||||
|
let seqOfFiveElements = seq { 1 .. 5 }
|
||||||
|
let concatenateTwoSeqs = emptySeq |> Seq.append seqOfFiveElements
|
||||||
|
let oddNumbers = seqFromTwoToFive |> Seq.filter(fun n -> n % 2 <> 0)
|
||||||
|
let doubleNumbers = oddNumbers |> Seq.map(fun n -> n + n)
|
||||||
|
|
||||||
|
// Lists
|
||||||
|
module Lists =
|
||||||
|
let emptyList1 = List.empty
|
||||||
|
let emptyList2 = [ ]
|
||||||
|
let listOfFiveElements = [ 1; 2; 3; 4; 5 ]
|
||||||
|
let listFromTwoToTen = [ 2..10 ]
|
||||||
|
let appendOneToEmptyList = 1::emptyList1
|
||||||
|
let concatenateTwoLists = listOfFiveElements @ listFromTwoToTen
|
||||||
|
let evenNumbers = listOfFiveElements |> List.filter(fun n -> n % 2 = 0)
|
||||||
|
let squareNumbers = evenNumbers |> List.map(fun n -> n * n)
|
||||||
|
|
||||||
|
// Sets
|
||||||
|
module Sets =
|
||||||
|
let emptySet = Set.empty<int>
|
||||||
|
let setWithOneItem = emptySet.Add 8
|
||||||
|
let setFromList = [ 1..10 ] |> Set.ofList
|
||||||
|
|
||||||
|
// Maps
|
||||||
|
module Maps =
|
||||||
|
let emptyMap = Map.empty<int, string>
|
||||||
|
let mapWithOneItem = emptyMap.Add(42, "the answer to the meaning of life")
|
||||||
|
let mapFromList = [ (1, "Hello"), (2, "World") ] |> Map.ofSeq
|
||||||
|
|
||||||
|
// Loops
|
||||||
|
module Loops =
|
||||||
|
let mutable a = 10
|
||||||
|
while (a < 20) do
|
||||||
|
printfn "value of a: %d" a
|
||||||
|
a <- a + 1
|
||||||
|
|
||||||
|
for i = 1 to 10 do
|
||||||
|
printf "%d " i
|
||||||
|
|
||||||
|
for i in [1..10] do
|
||||||
|
printfn "%d" i
|
||||||
|
|
||||||
|
// Class and inheritance
|
||||||
|
module Class_and_inheritance =
|
||||||
|
type Person(firstName, lastName, age) =
|
||||||
|
member this.FirstName = firstName
|
||||||
|
member this.LastName = lastName
|
||||||
|
member this.Age = age
|
||||||
|
|
||||||
|
member this.UpdateAge(n:int) =
|
||||||
|
Person(firstName, lastName, age + n)
|
||||||
|
|
||||||
|
override this.ToString() =
|
||||||
|
sprintf "%s %s" firstName lastName
|
||||||
|
|
||||||
|
|
||||||
|
type Student(firstName, lastName, age, grade) =
|
||||||
|
inherit Person(firstName, lastName, age)
|
||||||
|
|
||||||
|
member this.Grade = grade
|
||||||
|
|
||||||
|
// Abstract classes and inheritance
|
||||||
|
module Abstract_class_and_inheritance =
|
||||||
|
[<AbstractClass>]
|
||||||
|
type Shape(weight :float, height :float) =
|
||||||
|
member this.Weight = weight
|
||||||
|
member this.Height = height
|
||||||
|
|
||||||
|
abstract member Area : unit -> float
|
||||||
|
default this.Area() = weight * height
|
||||||
|
|
||||||
|
type Rectangle(weight :float, height :float) =
|
||||||
|
inherit Shape(weight, height)
|
||||||
|
|
||||||
|
type Circle(radius :float) =
|
||||||
|
inherit Shape(radius, radius)
|
||||||
|
override this.Area() = radius * radius * Math.PI
|
||||||
|
|
||||||
|
// Interfaces
|
||||||
|
module Interfaces =
|
||||||
|
type IPerson =
|
||||||
|
abstract FirstName : string
|
||||||
|
abstract LastName : string
|
||||||
|
abstract FullName : unit -> string
|
||||||
|
|
||||||
|
type Person(firstName : string, lastName : string) =
|
||||||
|
interface IPerson with
|
||||||
|
member this.FirstName = firstName
|
||||||
|
member this.LastName = lastName
|
||||||
|
member this.FullName() = sprintf "%s %s" firstName lastName
|
||||||
|
|
||||||
|
let fred = Person("Fred", "Flintstone")
|
||||||
|
|
||||||
|
(fred :> IPerson).FullName()
|
||||||
|
|> ignore
|
||||||
|
|
||||||
|
// Object expressions
|
||||||
|
module Object_expressions =
|
||||||
|
let print color =
|
||||||
|
let current = Console.ForegroundColor
|
||||||
|
Console.ForegroundColor <- color
|
||||||
|
{ new IDisposable with
|
||||||
|
member x.Dispose() =
|
||||||
|
Console.ForegroundColor <- current
|
||||||
|
}
|
||||||
|
|
||||||
|
using(print ConsoleColor.Red) (fun _ -> printf "Hello in red!!")
|
||||||
|
using(print ConsoleColor.Blue) (fun _ -> printf "Hello in blue!!")
|
||||||
|
|
||||||
|
// Casting
|
||||||
|
module Castings =
|
||||||
|
open Interfaces
|
||||||
|
|
||||||
|
let testPersonType (o:obj) =
|
||||||
|
match o with
|
||||||
|
| :? IPerson as person -> printfn "this object is an IPerson"
|
||||||
|
| _ -> printfn "this is not an IPerson"
|
||||||
|
|
||||||
|
// Units of Measure
|
||||||
|
module Measure =
|
||||||
|
[<Measure>]
|
||||||
|
type m
|
||||||
|
|
||||||
|
[<Measure>]
|
||||||
|
type sec
|
||||||
|
|
||||||
|
let distance = 25.0<m>
|
||||||
|
let time = 10.0<sec>
|
||||||
|
|
||||||
|
let speed = distance / time
|
||||||
|
|
||||||
|
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main argv =
|
||||||
|
printfn "%A" argv
|
||||||
|
0
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
<package id="System.ValueTuple" version="4.4.0" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8" ?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,63 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{1F277609-5767-4E49-B243-35B3139E4B98}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>AsyncInterop.CS</RootNamespace>
|
||||||
|
<AssemblyName>AsyncInterop.CS</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\AsyncInteroperability\AsyncInteroperability.fsproj">
|
||||||
|
<Project>{9336b874-f0b2-4923-8f4b-a0753b9eb0ba}</Project>
|
||||||
|
<Name>AsyncInteroperability</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
</Project>
|
|
@ -0,0 +1,25 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using AsyncInterop;
|
||||||
|
using static AsyncInterop.AsyncInteropDownload;
|
||||||
|
|
||||||
|
namespace AsyncInterop.CS
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static async Task DownloadMediaAsync()
|
||||||
|
{
|
||||||
|
var cts = new CancellationToken();
|
||||||
|
var images = await downloadMediaAsyncParallel("MyMedia").AsTask(cts);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
using System.Reflection;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[assembly: AssemblyTitle("AsyncInterop.CS")]
|
||||||
|
[assembly: AssemblyDescription("")]
|
||||||
|
[assembly: AssemblyConfiguration("")]
|
||||||
|
[assembly: AssemblyCompany("")]
|
||||||
|
[assembly: AssemblyProduct("AsyncInterop.CS")]
|
||||||
|
[assembly: AssemblyCopyright("Copyright © 2018")]
|
||||||
|
[assembly: AssemblyTrademark("")]
|
||||||
|
[assembly: AssemblyCulture("")]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[assembly: ComVisible(false)]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[assembly: Guid("1f277609-5767-4e49-b243-35b3139e4b98")]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [assembly: AssemblyVersion("1.0.*")]
|
||||||
|
[assembly: AssemblyVersion("1.0.0.0")]
|
||||||
|
[assembly: AssemblyFileVersion("1.0.0.0")]
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,41 @@
|
||||||
|
namespace AsyncInteroperability.AssemblyInfo
|
||||||
|
|
||||||
|
open System.Reflection
|
||||||
|
open System.Runtime.CompilerServices
|
||||||
|
open System.Runtime.InteropServices
|
||||||
|
|
||||||
|
// General Information about an assembly is controlled through the following
|
||||||
|
// set of attributes. Change these attribute values to modify the information
|
||||||
|
// associated with an assembly.
|
||||||
|
[<assembly: AssemblyTitle("AsyncInteroperability")>]
|
||||||
|
[<assembly: AssemblyDescription("")>]
|
||||||
|
[<assembly: AssemblyConfiguration("")>]
|
||||||
|
[<assembly: AssemblyCompany("")>]
|
||||||
|
[<assembly: AssemblyProduct("AsyncInteroperability")>]
|
||||||
|
[<assembly: AssemblyCopyright("Copyright © 2018")>]
|
||||||
|
[<assembly: AssemblyTrademark("")>]
|
||||||
|
[<assembly: AssemblyCulture("")>]
|
||||||
|
|
||||||
|
// Setting ComVisible to false makes the types in this assembly not visible
|
||||||
|
// to COM components. If you need to access a type in this assembly from
|
||||||
|
// COM, set the ComVisible attribute to true on that type.
|
||||||
|
[<assembly: ComVisible(false)>]
|
||||||
|
|
||||||
|
// The following GUID is for the ID of the typelib if this project is exposed to COM
|
||||||
|
[<assembly: Guid("9336b874-f0b2-4923-8f4b-a0753b9eb0ba")>]
|
||||||
|
|
||||||
|
// Version information for an assembly consists of the following four values:
|
||||||
|
//
|
||||||
|
// Major Version
|
||||||
|
// Minor Version
|
||||||
|
// Build Number
|
||||||
|
// Revision
|
||||||
|
//
|
||||||
|
// You can specify all the values or you can default the Build and Revision Numbers
|
||||||
|
// by using the '*' as shown below:
|
||||||
|
// [<assembly: AssemblyVersion("1.0.*")>]
|
||||||
|
[<assembly: AssemblyVersion("1.0.0.0")>]
|
||||||
|
[<assembly: AssemblyFileVersion("1.0.0.0")>]
|
||||||
|
|
||||||
|
do
|
||||||
|
()
|
|
@ -0,0 +1,56 @@
|
||||||
|
namespace AsyncInterop
|
||||||
|
open System
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open System.Runtime.CompilerServices
|
||||||
|
|
||||||
|
module private AsyncInterop =
|
||||||
|
|
||||||
|
let asTask(async: Async<'T>, token: CancellationToken option) =
|
||||||
|
let tcs = TaskCompletionSource<'T>()
|
||||||
|
let token = defaultArg token Async.DefaultCancellationToken
|
||||||
|
Async.StartWithContinuations(async,
|
||||||
|
tcs.SetResult,
|
||||||
|
tcs.SetException,
|
||||||
|
tcs.SetException, token)
|
||||||
|
tcs.Task
|
||||||
|
|
||||||
|
let asAsync(task: Task, token: CancellationToken option) =
|
||||||
|
Async.FromContinuations( //
|
||||||
|
fun (completed, caught, canceled) ->
|
||||||
|
let token = defaultArg token Async.DefaultCancellationToken
|
||||||
|
task.ContinueWith(new Action<Task>(fun _ ->
|
||||||
|
if task.IsFaulted then caught(task.Exception)
|
||||||
|
else if task.IsCanceled then
|
||||||
|
canceled(new OperationCanceledException(token)|>raise)
|
||||||
|
else completed()), token)
|
||||||
|
|> ignore)
|
||||||
|
|
||||||
|
let asAsyncT(task: Task<'T>, token: CancellationToken option) =
|
||||||
|
Async.FromContinuations(
|
||||||
|
fun (completed, caught, canceled) ->
|
||||||
|
let token = defaultArg token Async.DefaultCancellationToken
|
||||||
|
task.ContinueWith(new Action<Task<'T>>(fun _ ->
|
||||||
|
if task.IsFaulted then caught(task.Exception)
|
||||||
|
else if task.IsCanceled then
|
||||||
|
canceled(OperationCanceledException(token) |> raise)
|
||||||
|
else completed(task.Result)), token)
|
||||||
|
|> ignore)
|
||||||
|
|
||||||
|
[<Extension>]
|
||||||
|
type AsyncInteropExtensions =
|
||||||
|
[<Extension>]
|
||||||
|
static member AsAsync (task: Task<'T>) = AsyncInterop.asAsyncT (task, None)
|
||||||
|
|
||||||
|
[<Extension>]
|
||||||
|
static member AsAsync (task: Task<'T>, token: CancellationToken) =
|
||||||
|
AsyncInterop.asAsyncT (task, Some token)
|
||||||
|
|
||||||
|
[<Extension>]
|
||||||
|
static member AsTask (async: Async<'T>) = AsyncInterop.asTask (async, None)
|
||||||
|
|
||||||
|
[<Extension>]
|
||||||
|
static member AsTask (async: Async<'T>, token: CancellationToken) =
|
||||||
|
AsyncInterop.asTask (async, Some token)
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,30 @@
|
||||||
|
namespace AsyncInterop
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open System.Runtime.CompilerServices
|
||||||
|
open AsyncInterop
|
||||||
|
open Microsoft.WindowsAzure.Storage
|
||||||
|
open System.IO
|
||||||
|
|
||||||
|
module AsyncInteropDownload =
|
||||||
|
|
||||||
|
let azureConnection = "< AZURE CONNECTION >"
|
||||||
|
|
||||||
|
let downloadMediaAsyncParallel containerName = async {
|
||||||
|
let storageAccount = CloudStorageAccount.Parse(azureConnection)
|
||||||
|
let blobClient = storageAccount.CreateCloudBlobClient()
|
||||||
|
let container = blobClient.GetContainerReference(containerName)
|
||||||
|
let computations =
|
||||||
|
container.ListBlobs()
|
||||||
|
|> Seq.map(fun blobMedia -> async {
|
||||||
|
let blobName = blobMedia.Uri.Segments.
|
||||||
|
[blobMedia.Uri.Segments.Length - 1]
|
||||||
|
let blockBlob = container.GetBlockBlobReference(blobName)
|
||||||
|
use stream = new MemoryStream()
|
||||||
|
do! blockBlob.DownloadToStreamAsync(stream) |> Async.AwaitTask
|
||||||
|
let image = System.Drawing.Bitmap.FromStream(stream)
|
||||||
|
return image })
|
||||||
|
return! Async.Parallel computations }
|
||||||
|
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="15.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>9336b874-f0b2-4923-8f4b-a0753b9eb0ba</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>AsyncInteroperability</RootNamespace>
|
||||||
|
<AssemblyName>AsyncInteroperability</AssemblyName>
|
||||||
|
<UseStandardResourceNames>true</UseStandardResourceNames>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<Name>AsyncInteroperability</Name>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<DocumentationFile>bin\$(Configuration)\$(AssemblyName).XML</DocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\$(Configuration)\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<DocumentationFile>bin\$(Configuration)\$(AssemblyName).XML</DocumentationFile>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(FSharpTargetsPath)' == '' AND Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets') ">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="AssemblyInfo.fs" />
|
||||||
|
<Compile Include="AsyncInterop,fs.fs" />
|
||||||
|
<Compile Include="AsyncInteropDownload.fs" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Data.Edm">
|
||||||
|
<HintPath>..\..\packages\Microsoft.Data.Edm.5.6.0\lib\net40\Microsoft.Data.Edm.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Data.OData">
|
||||||
|
<HintPath>..\..\packages\Microsoft.Data.OData.5.6.0\lib\net40\Microsoft.Data.OData.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.Data.Services.Client">
|
||||||
|
<HintPath>..\..\packages\Microsoft.Data.Services.Client.5.6.0\lib\net40\Microsoft.Data.Services.Client.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.WindowsAzure.Configuration">
|
||||||
|
<HintPath>..\..\packages\Microsoft.WindowsAzure.ConfigurationManager.1.8.0.0\lib\net35-full\Microsoft.WindowsAzure.Configuration.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="Microsoft.WindowsAzure.Storage">
|
||||||
|
<HintPath>..\..\packages\WindowsAzure.Storage.4.0.1\lib\net40\Microsoft.WindowsAzure.Storage.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="Newtonsoft.Json">
|
||||||
|
<HintPath>..\..\packages\Newtonsoft.Json.5.0.6\lib\net45\Newtonsoft.Json.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Spatial">
|
||||||
|
<HintPath>..\..\packages\System.Spatial.5.6.0\lib\net40\System.Spatial.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.ValueTuple">
|
||||||
|
<HintPath>..\..\packages\System.ValueTuple.4.4.0\lib\net47\System.ValueTuple.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,12 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
<package id="Microsoft.Data.Edm" version="5.6.0" targetFramework="net47" />
|
||||||
|
<package id="Microsoft.Data.OData" version="5.8.4" targetFramework="net47" />
|
||||||
|
<package id="Microsoft.Data.Services.Client" version="5.6.0" targetFramework="net47" />
|
||||||
|
<package id="Microsoft.WindowsAzure.ConfigurationManager" version="1.8.0.0" targetFramework="net47" />
|
||||||
|
<package id="Newtonsoft.Json" version="5.0.6" targetFramework="net47" />
|
||||||
|
<package id="System.Spatial" version="5.6.0" targetFramework="net47" />
|
||||||
|
<package id="System.ValueTuple" version="4.4.0" targetFramework="net47" />
|
||||||
|
<package id="WindowsAzure.Storage" version="4.0.1" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace QuickSort.cs
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Random rand = new Random((int) DateTime.Now.Ticks);
|
||||||
|
int attempts = 5;
|
||||||
|
int[][] dataSamples =
|
||||||
|
Enumerable.Range(0, attempts)
|
||||||
|
.Select(x =>
|
||||||
|
{
|
||||||
|
var A = new int[1000000];
|
||||||
|
for (int i = 0; i < 1000000; ++i)
|
||||||
|
A[i] = rand.Next();
|
||||||
|
return A;
|
||||||
|
}).ToArray();
|
||||||
|
|
||||||
|
Func<Action<int[]>, Action[]> run = (sortFunc) =>
|
||||||
|
dataSamples.Select(data => (Action)(() => sortFunc(data))).ToArray();
|
||||||
|
|
||||||
|
var implementations =
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"Sequential", run(QuickSort.QuickSort_Sequential)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"Parallel", run(QuickSort.QuickSort_Parallel)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"ParallelWithDepth", run(QuickSort.QuickSort_Parallel_Threshold)),
|
||||||
|
};
|
||||||
|
|
||||||
|
Application.Run(
|
||||||
|
PerfVis.toChart("C# QuickSort")
|
||||||
|
.Invoke(PerfVis.fromTuples(implementations)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace QuickSort.cs
|
||||||
|
{
|
||||||
|
public class QuickSort
|
||||||
|
{
|
||||||
|
public static void QuickSort_Sequential<T>(T[] items) where T : IComparable<T>
|
||||||
|
=> QuickSort_Sequential(items, 0, items.Length);
|
||||||
|
|
||||||
|
private static void QuickSort_Sequential<T>(T[] items, int left, int right) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (left == right) return;
|
||||||
|
int pivot = Partition(items, left, right);
|
||||||
|
QuickSort_Sequential(items, left, pivot);
|
||||||
|
QuickSort_Sequential(items, pivot + 1, right);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static int Partition<T>(T[] items, int left, int right) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
int pivotPos = (right + left) / 2; // often a random index between left and right is used
|
||||||
|
T pivotValue = items[pivotPos];
|
||||||
|
|
||||||
|
Swap(ref items[right - 1], ref items[pivotPos]);
|
||||||
|
int store = left;
|
||||||
|
for (int i = left; i < right - 1; ++i)
|
||||||
|
{
|
||||||
|
if (items[i].CompareTo(pivotValue) < 0)
|
||||||
|
{
|
||||||
|
Swap(ref items[i], ref items[store]);
|
||||||
|
++store;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Swap(ref items[right - 1], ref items[store]);
|
||||||
|
return store;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void Swap<T>(ref T a, ref T b)
|
||||||
|
{
|
||||||
|
T temp = a;
|
||||||
|
a = b;
|
||||||
|
b = temp;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void QuickSort_Parallel<T>(T[] items) where T : IComparable<T>
|
||||||
|
=> QuickSort_Parallel(items, 0, items.Length);
|
||||||
|
|
||||||
|
private static void QuickSort_Parallel<T>(T[] items, int left, int right) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (right - left < 2)
|
||||||
|
{
|
||||||
|
if (left+1 == right &&
|
||||||
|
items[left].CompareTo(items[right-1]) > 0)
|
||||||
|
Swap(ref items[left], ref items[right-1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int pivot = Partition(items, left, right);
|
||||||
|
Task leftTask = Task.Run(() => QuickSort_Parallel(items, left, pivot));
|
||||||
|
Task rightTask = Task.Run(() => QuickSort_Parallel(items, pivot + 1, right));
|
||||||
|
Task.WaitAll(leftTask, rightTask);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void QuickSort_Parallel_Threshold<T>(T[] items) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
int maxDepth = (int) Math.Log(Environment.ProcessorCount, 2.0);
|
||||||
|
QuickSort_Parallel_Threshold(items, 0, items.Length, maxDepth);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static void QuickSort_Parallel_Threshold<T>(T[] items, int left, int right, int depth) where T : IComparable<T>
|
||||||
|
{
|
||||||
|
if (right - left < 2)
|
||||||
|
{
|
||||||
|
if (left + 1 == right &&
|
||||||
|
items[left].CompareTo(items[right-1]) > 0)
|
||||||
|
Swap(ref items[left], ref items[right-1]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
int pivot = Partition(items, left, right);
|
||||||
|
if (depth >= 0)
|
||||||
|
{
|
||||||
|
Parallel.Invoke(
|
||||||
|
() => QuickSort_Parallel_Threshold(items, left, pivot, depth - 1),
|
||||||
|
() => QuickSort_Parallel_Threshold(items, pivot + 1, right, depth - 1)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
QuickSort_Parallel_Threshold(items, left, pivot, depth);
|
||||||
|
QuickSort_Parallel_Threshold(items, pivot + 1, right, depth);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{BB41293F-CA44-4AE9-8198-AB1F2A0D71A5}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>QuickSort.cs</RootNamespace>
|
||||||
|
<AssemblyName>QuickSort.cs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="QuickSort.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,26 @@
|
||||||
|
open System
|
||||||
|
open System.Windows.Forms
|
||||||
|
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main argv =
|
||||||
|
|
||||||
|
let rand = Random(int(DateTime.Now.Ticks))
|
||||||
|
let attempts = 5
|
||||||
|
let dataSamples =
|
||||||
|
List.init attempts (fun _ ->
|
||||||
|
List.init 1000000 (fun i -> rand.Next()))
|
||||||
|
let run sort =
|
||||||
|
dataSamples
|
||||||
|
|> List.map (fun data ->
|
||||||
|
fun () -> sort data |> ignore
|
||||||
|
)
|
||||||
|
|
||||||
|
[
|
||||||
|
"Sequential" , run QuickSort.quicksortSequential
|
||||||
|
"Parallel" , run QuickSort.quicksortParallel
|
||||||
|
"ParallelWithDepth" , run (QuickSort.quicksortParallelWithDepth QuickSort.ParallelismHelpers.MaxDepth)
|
||||||
|
]
|
||||||
|
|> PerfVis.toChart "F# QuickSort"
|
||||||
|
|> Application.Run
|
||||||
|
|
||||||
|
0
|
|
@ -0,0 +1,50 @@
|
||||||
|
module QuickSort
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading.Tasks
|
||||||
|
|
||||||
|
type ParallelismHelpers =
|
||||||
|
static member MaxDepth =
|
||||||
|
int (Math.Log(float Environment.ProcessorCount, 2.0))
|
||||||
|
|
||||||
|
static member TotalWorkers =
|
||||||
|
int (2.0 ** float (ParallelismHelpers.MaxDepth))
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 1.1 A simple Quick-sort Algorithm
|
||||||
|
let rec quicksortSequential aList =
|
||||||
|
match aList with
|
||||||
|
| [] -> []
|
||||||
|
| firstElement :: restOfList ->
|
||||||
|
let smaller, larger =
|
||||||
|
List.partition (fun number -> number > firstElement) restOfList
|
||||||
|
quicksortSequential smaller @ (firstElement :: quicksortSequential larger)
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 1.2 A parallel Quick-Sort Algorithm using the TPL library
|
||||||
|
let rec quicksortParallel aList =
|
||||||
|
match aList with
|
||||||
|
| [] -> []
|
||||||
|
| firstElement :: restOfList ->
|
||||||
|
let smaller, larger =
|
||||||
|
List.partition (fun number -> number > firstElement) restOfList
|
||||||
|
let left = Task.Run(fun () -> quicksortParallel smaller) // #A
|
||||||
|
let right = Task.Run(fun () -> quicksortParallel larger) // #A
|
||||||
|
left.Result @ (firstElement :: right.Result) // #B
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 1.3 A better parallel Quick-Sort Algorithm using the TPL library
|
||||||
|
let rec quicksortParallelWithDepth depth aList = // #A
|
||||||
|
match aList with
|
||||||
|
| [] -> []
|
||||||
|
| firstElement :: restOfList ->
|
||||||
|
let smaller, larger =
|
||||||
|
List.partition (fun number -> number > firstElement) restOfList
|
||||||
|
if depth < 0 then // #B
|
||||||
|
let left = quicksortParallelWithDepth depth smaller //#C
|
||||||
|
let right = quicksortParallelWithDepth depth larger //#C
|
||||||
|
left @ (firstElement :: right)
|
||||||
|
else
|
||||||
|
let left = Task.Run(fun () -> quicksortParallelWithDepth (depth - 1) smaller) // #D
|
||||||
|
let right = Task.Run(fun () -> quicksortParallelWithDepth (depth - 1) larger) // #D
|
||||||
|
left.Result @ (firstElement :: right.Result)
|
|
@ -0,0 +1,85 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>85d58f6a-d2ee-4b6f-a19a-3f9cc1babf6a</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>QuickSort.fs</RootNamespace>
|
||||||
|
<AssemblyName>QuickSort.fs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFSharpCoreVersion>4.4.3.0</TargetFSharpCoreVersion>
|
||||||
|
<Name>QuickSort.fs</Name>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Debug\QuickSort.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Release\QuickSort.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="QuickSort.fs" />
|
||||||
|
<Compile Include="Program.fs" />
|
||||||
|
<None Include="App.config" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,81 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Media;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
class Closure
|
||||||
|
{
|
||||||
|
// Listing 2.5 Closure defined in C# using an anonymous method
|
||||||
|
public void FreeVariable()
|
||||||
|
{
|
||||||
|
string freeVariable = "I am a free variable"; //#A
|
||||||
|
Func<string, string> lambda = value => freeVariable + " " + value; //#B
|
||||||
|
}
|
||||||
|
|
||||||
|
System.Windows.Controls.Image img;
|
||||||
|
// Listing 2.6 Event register with lambda expression capturing local variable
|
||||||
|
void UpdateImage(string url)
|
||||||
|
{
|
||||||
|
System.Windows.Controls.Image image = img; //#A
|
||||||
|
|
||||||
|
var client = new WebClient();
|
||||||
|
client.DownloadDataCompleted += (o, e) => //#B
|
||||||
|
{
|
||||||
|
if (image != null)
|
||||||
|
using (var ms = new MemoryStream(e.Result))
|
||||||
|
{
|
||||||
|
var imageConverter = new ImageSourceConverter();
|
||||||
|
image.Source = (ImageSource) imageConverter.ConvertFrom(ms);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
client.DownloadDataAsync(new Uri(url)); //#C
|
||||||
|
|
||||||
|
// image = null; //#A from Listing 2.7
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing 2.8 Closure capturing variables in a multi-threaded environment
|
||||||
|
public void Closure_Strange_Behavior()
|
||||||
|
{
|
||||||
|
int iterations = 10;
|
||||||
|
for (int i = 1; i <= iterations; i++)
|
||||||
|
{
|
||||||
|
Task.Factory.StartNew(() =>
|
||||||
|
Console.WriteLine("{0} - {1}", Thread.CurrentThread.ManagedThreadId, i));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Closure_Correct_Behavior()
|
||||||
|
{
|
||||||
|
int iterations = 10;
|
||||||
|
for (int i = 1; i <= iterations; i++)
|
||||||
|
{
|
||||||
|
var index = i;
|
||||||
|
Task.Factory.StartNew(() =>
|
||||||
|
Console.WriteLine("{0} - {1}", Thread.CurrentThread.ManagedThreadId, index));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing 2.9 Function to calculate the area of a triangle
|
||||||
|
void CalcluateAreaFunction()
|
||||||
|
{
|
||||||
|
Action<int> displayNumber = n => Console.WriteLine(n);
|
||||||
|
|
||||||
|
int i = 5;
|
||||||
|
|
||||||
|
Task taskOne = Task.Factory.StartNew(() => displayNumber(i));
|
||||||
|
|
||||||
|
i = 7;
|
||||||
|
|
||||||
|
Task taskTwo = Task.Factory.StartNew(() => displayNumber(i));
|
||||||
|
|
||||||
|
Task.WaitAll(taskOne, taskTwo);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
static class Composition
|
||||||
|
{
|
||||||
|
// Listing 2.3 Compose function in C#
|
||||||
|
static Func<A, C> Compose<A, B, C>(this Func<A, B> f, Func<B, C> g) => (n) => g(f(n));
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
using FuzzyMatch;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
struct Temperature
|
||||||
|
{
|
||||||
|
Temperature(float temperature)
|
||||||
|
{
|
||||||
|
Temp = temperature;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Temp { get; }
|
||||||
|
|
||||||
|
}
|
||||||
|
class ConcurrentSpeculation
|
||||||
|
{
|
||||||
|
// Listing 2.22 A fuzzy match
|
||||||
|
public static string FuzzyMatch(List<string> words, string word)
|
||||||
|
{
|
||||||
|
var wordSet = new HashSet<string>(words); //#A
|
||||||
|
|
||||||
|
string bestMatch =
|
||||||
|
(from w in wordSet.AsParallel() //#B
|
||||||
|
select JaroWinklerModule.Match(w, word))
|
||||||
|
.OrderByDescending(w => w.Distance)
|
||||||
|
.Select(w => w.Word)
|
||||||
|
.FirstOrDefault();
|
||||||
|
return bestMatch; //#C
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing 2.23 Fast Fuzzy Match using precomputation
|
||||||
|
public static Func<string, string> PartialFuzzyMatch(List<string> words) //#A
|
||||||
|
{
|
||||||
|
var wordSet = new HashSet<string>(words); //#B
|
||||||
|
|
||||||
|
return word =>
|
||||||
|
(from w in wordSet.AsParallel()
|
||||||
|
select JaroWinklerModule.Match(w, word))
|
||||||
|
.OrderByDescending(w => w.Distance)
|
||||||
|
.Select(w => w.Word)
|
||||||
|
.FirstOrDefault(); //#C
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void FuzzyMatchDemo()
|
||||||
|
{
|
||||||
|
List<string> words =
|
||||||
|
System.IO.File
|
||||||
|
.ReadAllLines("google-10000-english/google-10000-english.txt")
|
||||||
|
.Where(x=>
|
||||||
|
!(x.Equals("magic", StringComparison.InvariantCultureIgnoreCase)) &&
|
||||||
|
!(x.Equals("light", StringComparison.InvariantCultureIgnoreCase)))
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
// Listing 2.22 A fuzzy match
|
||||||
|
Demo.Benchmark("Listing 2.22 A fuzzy match", () =>
|
||||||
|
{
|
||||||
|
string fuzzyMatch = ConcurrentSpeculation.FuzzyMatch(words, "magic"); //#D
|
||||||
|
|
||||||
|
Console.WriteLine($"FuzzyMatch for 'magic' = {fuzzyMatch}");
|
||||||
|
});
|
||||||
|
|
||||||
|
Demo.Benchmark("Listing 2.23 Fast Fuzzy Match using precomputation", () =>
|
||||||
|
{
|
||||||
|
Func<string, string> fastFuzzyMatch = PartialFuzzyMatch(words); //#D
|
||||||
|
|
||||||
|
string magicFuzzyMatch = fastFuzzyMatch("magic");
|
||||||
|
string lightFuzzyMatch = fastFuzzyMatch("light"); //#E
|
||||||
|
|
||||||
|
Console.WriteLine($"FastFuzzyMatch for 'magic' = {magicFuzzyMatch}");
|
||||||
|
Console.WriteLine($"FastFuzzyMatch for 'light' = {lightFuzzyMatch}");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 2.25 Fastest weather task
|
||||||
|
public Temperature SpeculativeTempCityQuery(string city, params Uri[] weatherServices)
|
||||||
|
{
|
||||||
|
var cts = new CancellationTokenSource(); //#A
|
||||||
|
var tasks =
|
||||||
|
(from uri in weatherServices
|
||||||
|
select Task.Factory.StartNew<Temperature>(() =>
|
||||||
|
queryService(uri, city), cts.Token)).ToArray(); //#B
|
||||||
|
|
||||||
|
int taskIndex = Task.WaitAny(tasks); //#C
|
||||||
|
Temperature tempCity = tasks[taskIndex].Result;
|
||||||
|
cts.Cancel(); //#D
|
||||||
|
return tempCity;
|
||||||
|
}
|
||||||
|
|
||||||
|
private Temperature queryService(Uri uri, string city)
|
||||||
|
{
|
||||||
|
throw new NotImplementedException();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{22D90FF3-0F4D-468B-ABA1-1CD6A82D16DA}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>FunctionalTechniques.cs</RootNamespace>
|
||||||
|
<AssemblyName>FunctionalTechniques.cs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="PresentationCore" />
|
||||||
|
<Reference Include="PresentationFramework" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Xaml" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
<Reference Include="WindowsBase" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\..\Common\Functional.cs\Memoize.cs">
|
||||||
|
<Link>Memoize.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="Closure.cs" />
|
||||||
|
<Compile Include="Composition.cs" />
|
||||||
|
<Compile Include="Laziness.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="ConcurrentSpeculation.cs" />
|
||||||
|
<Compile Include="WeakMemoization.cs" />
|
||||||
|
<Compile Include="WebCrawler.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="google-10000-english\LICENSE.md" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="google-10000-english\google-10000-english.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,73 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Data.SqlClient;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
// Listing 2.26 Lazy initialization of the Person object
|
||||||
|
public class Person //#A
|
||||||
|
{
|
||||||
|
public readonly string FullName; //#B
|
||||||
|
public Person(string firstName, string lastName)
|
||||||
|
{
|
||||||
|
FullName = firstName + " " + lastName;
|
||||||
|
Console.WriteLine(FullName);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RunDemo()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Listing 2.26 Lazy initialization of the Person object");
|
||||||
|
Lazy<Person> fredFlintstone =
|
||||||
|
new Lazy<Person>(() => new Person("Fred", "Flintstone"), true); //#B
|
||||||
|
|
||||||
|
Person[] freds = new Person[5]; //#C
|
||||||
|
for (int i = 0; i < freds.Length; i++) //#D
|
||||||
|
{
|
||||||
|
freds[i] = fredFlintstone.Value; //#E
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing 2.27 Singleton pattern using Lazy<T>
|
||||||
|
public sealed class Singleton
|
||||||
|
{
|
||||||
|
private static readonly Lazy<Singleton> lazy =
|
||||||
|
new Lazy<Singleton>(() => new Singleton(), true); //#A
|
||||||
|
|
||||||
|
public static Singleton Instance => lazy.Value;
|
||||||
|
|
||||||
|
private Singleton()
|
||||||
|
{ }
|
||||||
|
}
|
||||||
|
|
||||||
|
class Laziness
|
||||||
|
{
|
||||||
|
static string cmdText = null;
|
||||||
|
static SqlConnection conn = null;
|
||||||
|
|
||||||
|
// Listing 2.29 Lazy asynchronous operation to initialize the Person object
|
||||||
|
Lazy<Task<Person>> person =
|
||||||
|
new Lazy<Task<Person>>(async () => // #A
|
||||||
|
{
|
||||||
|
using (var cmd = new SqlCommand(cmdText, conn))
|
||||||
|
using (var reader = await cmd.ExecuteReaderAsync())
|
||||||
|
{
|
||||||
|
if (await reader.ReadAsync())
|
||||||
|
{
|
||||||
|
string firstName = reader["first_name"].ToString();
|
||||||
|
string lastName = reader["last_name"].ToString();
|
||||||
|
return new Person(firstName, lastName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
throw new Exception("Failed to fetch Person");
|
||||||
|
});
|
||||||
|
|
||||||
|
async Task<Person> FetchPerson()
|
||||||
|
{
|
||||||
|
return await person.Value; // #B
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
// Listing 2.14 Greeting example in C#
|
||||||
|
public static string Greeting(string name)
|
||||||
|
{
|
||||||
|
return $"Warm greetings {name}, the time is {DateTime.Now.ToString("hh:mm:ss")}";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RunDemoMemoization()
|
||||||
|
{
|
||||||
|
Console.WriteLine("Listing 2.14 Greeting example in C#");
|
||||||
|
Console.WriteLine(Greeting("Richard"));
|
||||||
|
System.Threading.Thread.Sleep(2000);
|
||||||
|
Console.WriteLine(Greeting("Paul"));
|
||||||
|
System.Threading.Thread.Sleep(2000);
|
||||||
|
Console.WriteLine(Greeting("Richard"));
|
||||||
|
|
||||||
|
Console.WriteLine("\nListing 2.15 Greeting example using memoized function");
|
||||||
|
var greetingMemoize = Memoization.Memoize<string, string>(Greeting); //#A
|
||||||
|
|
||||||
|
Console.WriteLine(greetingMemoize("Richard")); //#B
|
||||||
|
System.Threading.Thread.Sleep(2000);
|
||||||
|
Console.WriteLine(greetingMemoize("Paul"));
|
||||||
|
System.Threading.Thread.Sleep(2000);
|
||||||
|
Console.WriteLine(greetingMemoize("Richard")); //#B
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Closure closure = new Closure();
|
||||||
|
closure.Closure_Strange_Behavior();
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
closure.Closure_Correct_Behavior();
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
|
||||||
|
RunDemoMemoization();
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
|
||||||
|
WebCrawlerExample.RunDemo();
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
|
||||||
|
ConcurrentSpeculation.FuzzyMatchDemo();
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
|
||||||
|
Person.RunDemo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,55 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Runtime.CompilerServices;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
public static partial class Memoization
|
||||||
|
{
|
||||||
|
public static Func<T, R> MemoizeWeakWithTtl<T, R>(Func<T, R> func, TimeSpan ttl)
|
||||||
|
where T : class, IEquatable<T>
|
||||||
|
where R : class
|
||||||
|
{
|
||||||
|
var keyStore = new ConcurrentDictionary<int, T>();
|
||||||
|
|
||||||
|
T ReduceKey(T obj)
|
||||||
|
{
|
||||||
|
var oldObj = keyStore.GetOrAdd(obj.GetHashCode(), obj);
|
||||||
|
return obj.Equals(oldObj) ? oldObj : obj;
|
||||||
|
}
|
||||||
|
|
||||||
|
var cache = new ConditionalWeakTable<T, Tuple<R, DateTime>>();
|
||||||
|
|
||||||
|
Tuple<R, DateTime> FactoryFunc(T key) =>
|
||||||
|
new Tuple<R, DateTime>(func(key), DateTime.Now + ttl);
|
||||||
|
|
||||||
|
return arg =>
|
||||||
|
{
|
||||||
|
var key = ReduceKey(arg);
|
||||||
|
var value = cache.GetValue(key, FactoryFunc);
|
||||||
|
if (value.Item2 >= DateTime.Now)
|
||||||
|
return value.Item1;
|
||||||
|
value = FactoryFunc(key);
|
||||||
|
cache.Remove(key);
|
||||||
|
cache.Add(key, value);
|
||||||
|
return value.Item1;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public static void Example()
|
||||||
|
{
|
||||||
|
string Greeting(String name)
|
||||||
|
{
|
||||||
|
return $"Warm greetings {name}, the time is {DateTime.Now:hh:mm:ss}";
|
||||||
|
}
|
||||||
|
|
||||||
|
var greetingMemoize = MemoizeWeakWithTtl<string, string>(Greeting, TimeSpan.FromDays(1.0));
|
||||||
|
|
||||||
|
Console.WriteLine(greetingMemoize("Richard"));
|
||||||
|
System.Threading.Thread.Sleep(1500);
|
||||||
|
Console.WriteLine(greetingMemoize("_Richard".Substring(1)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,106 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Net;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
|
|
||||||
|
namespace FunctionalTechniques.cs
|
||||||
|
{
|
||||||
|
// Listing 2.16 Web crawler in C#
|
||||||
|
public class WebCrawlerExample
|
||||||
|
{
|
||||||
|
// Listing 2.18 Web crawler execution using memoization
|
||||||
|
// Listing 2.18 Web crawler execution using memoization
|
||||||
|
public static Func<string, IEnumerable<string>> WebCrawlerMemoized =
|
||||||
|
Memoization.Memoize<string, IEnumerable<string>>(WebCrawler); // #A
|
||||||
|
|
||||||
|
// Listing 2.20 Thread-safe memoization function
|
||||||
|
public static Func<string, IEnumerable<string>> WebCrawlerMemoizedThreadSafe =
|
||||||
|
Memoization.MemoizeThreadSafe<string, IEnumerable<string>>(WebCrawler);
|
||||||
|
|
||||||
|
public static IEnumerable<string> WebCrawler(string url) //#A
|
||||||
|
{
|
||||||
|
IEnumerable<string> WebCrawler(string webUrl)
|
||||||
|
{
|
||||||
|
var content = GetWebContent(webUrl);
|
||||||
|
yield return content;
|
||||||
|
|
||||||
|
foreach (var item in AnalyzeHtmlContent(content))
|
||||||
|
yield return GetWebContent(item);
|
||||||
|
}
|
||||||
|
|
||||||
|
return WebCrawler(url).ToList();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static string GetWebContent(string url)
|
||||||
|
{
|
||||||
|
using (var wc = new WebClient())
|
||||||
|
return wc.DownloadString(new Uri(url));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex regexLink = new Regex(@"(?<=href=('|""))https?://.*?(?=\1)");
|
||||||
|
|
||||||
|
private static IEnumerable<string> AnalyzeHtmlContent(string text)
|
||||||
|
{
|
||||||
|
foreach (var url in regexLink.Matches(text))
|
||||||
|
yield return url.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static readonly Regex regexTitle = new Regex("<title>(?<title>.*?)<\\/title>", RegexOptions.Compiled);
|
||||||
|
|
||||||
|
public static string ExtractWebPageTitle(string textPage) //#D
|
||||||
|
{
|
||||||
|
if (regexTitle.IsMatch(textPage))
|
||||||
|
return regexTitle.Match(textPage).Groups["title"].Value;
|
||||||
|
return "No Page Title Found!";
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void RunDemo()
|
||||||
|
{
|
||||||
|
List<string> urls = new List<string>
|
||||||
|
{
|
||||||
|
//#A
|
||||||
|
@"http://www.google.com",
|
||||||
|
@"http://www.microsoft.com",
|
||||||
|
@"http://www.bing.com",
|
||||||
|
@"http://www.google.com"
|
||||||
|
};
|
||||||
|
|
||||||
|
Demo.Benchmark("Listing 2.17 Web crawler execution", () =>
|
||||||
|
{
|
||||||
|
var webPageTitles = from url in urls //#B
|
||||||
|
from pageContent in WebCrawler(url)
|
||||||
|
select ExtractWebPageTitle(pageContent);
|
||||||
|
|
||||||
|
Console.WriteLine($"Crawled {webPageTitles.Count()} page titles");
|
||||||
|
});
|
||||||
|
|
||||||
|
Demo.Benchmark("Listing 2.18 Web crawler execution using memoization", () =>
|
||||||
|
{
|
||||||
|
var webPageTitles = from url in urls //#B
|
||||||
|
from pageContent in WebCrawlerMemoized(url)
|
||||||
|
select ExtractWebPageTitle(pageContent);
|
||||||
|
|
||||||
|
Console.WriteLine($"Crawled {webPageTitles.Count()} page titles");
|
||||||
|
});
|
||||||
|
|
||||||
|
Demo.Benchmark("Listing 2.19 Web crawler query using PLINQ", () =>
|
||||||
|
{
|
||||||
|
var webPageTitles = from url in urls.AsParallel() //#A
|
||||||
|
from pageContent in WebCrawlerMemoized(url)
|
||||||
|
select ExtractWebPageTitle(pageContent);
|
||||||
|
|
||||||
|
Console.WriteLine($"Crawled {webPageTitles.Count()} page titles");
|
||||||
|
});
|
||||||
|
|
||||||
|
Demo.Benchmark("Listing 2.20 Thread-safe memoization function", () =>
|
||||||
|
{
|
||||||
|
var webPageTitles = from url in urls.AsParallel()
|
||||||
|
from pageContent in WebCrawlerMemoizedThreadSafe(url) //#B
|
||||||
|
select ExtractWebPageTitle(pageContent); //#C
|
||||||
|
|
||||||
|
Console.WriteLine($"Crawled {webPageTitles.Count()} page titles");
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,3 @@
|
||||||
|
Downloaded from https://github.com/first20hours/google-10000-english
|
||||||
|
|
||||||
|
Data files are derived from the *Google Web Trillion Word Corpus*, as described by [Thorsten Brants and Alex Franz](http://googleresearch.blogspot.com/2006/08/all-our-n-gram-are-belong-to-you.html), and distributed by the [Linguistic Data Consortium](http://www.ldc.upenn.edu/Catalog/CatalogEntry.jsp?catalogId=LDC2006T13). Subsets of this corpus distributed by [Peter Novig](http://norvig.com/ngrams/). Corpus editing and cleanup by Josh Kaufman.
|
File diff suppressed because it is too large
Load diff
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,77 @@
|
||||||
|
module FunctionalTechniques
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Threading.Tasks
|
||||||
|
open System.Collections.Generic
|
||||||
|
open System.Collections.Concurrent
|
||||||
|
open FSharp.Collections.ParallelSeq
|
||||||
|
open FuzzyMatch
|
||||||
|
open System.Linq
|
||||||
|
|
||||||
|
// Listing 2.4 F# support for function composition
|
||||||
|
module Composition =
|
||||||
|
let add4 x = x + 4 //#A
|
||||||
|
let multiplyBy3 x = x * 3 //#B
|
||||||
|
let list = [0..10] //#C
|
||||||
|
|
||||||
|
let newList = List.map(fun x -> multiplyBy3(add4(x))) list //#D
|
||||||
|
let newList' = list |> List.map(add4 >> multiplyBy3) //#E
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 2.10 Closure capturing variables in a multithreaded environment in F#
|
||||||
|
module Closure =
|
||||||
|
let tasks = Array.zeroCreate<Task> 10
|
||||||
|
|
||||||
|
for index = 1 to 10 do
|
||||||
|
tasks.[index - 1] <- Task.Factory.StartNew(fun () -> Console.WriteLine index)
|
||||||
|
|
||||||
|
module Memoization =
|
||||||
|
// Listing 2.13 Memoize function in F#
|
||||||
|
let memoize func =
|
||||||
|
let table = Dictionary<_,_>()
|
||||||
|
fun x -> if table.ContainsKey(x) then table.[x]
|
||||||
|
else
|
||||||
|
let result = func x
|
||||||
|
table.[x] <- result
|
||||||
|
result
|
||||||
|
|
||||||
|
let memoizeThreadSafe (func: 'a -> 'b) =
|
||||||
|
let table = ConcurrentDictionary<'a,'b>()
|
||||||
|
fun x -> table.GetOrAdd(x, func)
|
||||||
|
|
||||||
|
|
||||||
|
module ConsurrentSpeculation =
|
||||||
|
|
||||||
|
// Listing 2.24 Fast fuzzy match in F#
|
||||||
|
let fuzzyMatch (words:string list) =
|
||||||
|
let wordSet = new HashSet<string>(words) //#A
|
||||||
|
let partialFuzzyMatch word = //#B
|
||||||
|
query { for w in wordSet.AsParallel() do
|
||||||
|
select (JaroWinkler.getMatch w word) }
|
||||||
|
|> Seq.sortBy(fun x -> -x.Distance)
|
||||||
|
|> Seq.head
|
||||||
|
|
||||||
|
fun word -> partialFuzzyMatch word //#C
|
||||||
|
|
||||||
|
|
||||||
|
let words = [] // TODO: Fill the list
|
||||||
|
let fastFuzzyMatch = fuzzyMatch words //#D
|
||||||
|
|
||||||
|
let magicFuzzyMatch = fastFuzzyMatch "magic"
|
||||||
|
let lightFuzzyMatch = fastFuzzyMatch "light”" //#E
|
||||||
|
|
||||||
|
|
||||||
|
let fuzzyMatchPSeq (words:string list) =
|
||||||
|
let wordSet = new HashSet<string>(words)
|
||||||
|
fun word ->
|
||||||
|
wordSet
|
||||||
|
|> PSeq.map(fun w -> JaroWinkler.bestMatch word w)
|
||||||
|
|> PSeq.sortBy(fun x -> -x.Distance)
|
||||||
|
|> Seq.head
|
||||||
|
|
||||||
|
module Laziness =
|
||||||
|
open FunctionalTechniques.cs
|
||||||
|
|
||||||
|
// Listing 2.28 Lazy initialization of the Person object with F#
|
||||||
|
let barneyRubble = lazy( Person("barney", "rubble") ) //#A
|
||||||
|
printfn "%s" (barneyRubble.Force().FullName) //#B
|
|
@ -0,0 +1,95 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>224cf699-2662-4159-a0e8-ec40324e6d04</ProjectGuid>
|
||||||
|
<OutputType>Library</OutputType>
|
||||||
|
<RootNamespace>FunctionalTechniques.fs</RootNamespace>
|
||||||
|
<AssemblyName>FunctionalTechniques.fs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFSharpCoreVersion>4.4.3.0</TargetFSharpCoreVersion>
|
||||||
|
<Name>FunctionalTechniques.fs</Name>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Debug\FunctionalTechniques.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Release\FunctionalTechniques.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="FunctionalTechniques.fs" />
|
||||||
|
<None Include="App.config" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\FunctionalTechniques.cs\FunctionalTechniques.cs.csproj">
|
||||||
|
<Name>FunctionalTechniques.cs</Name>
|
||||||
|
<Project>{22d90ff3-0f4d-468b-aba1-1cd6a82d16da}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
<Reference Include="FSharp.Collections.ParallelSeq">
|
||||||
|
<HintPath>..\..\packages\FSharp.Collections.ParallelSeq.1.0.2\lib\net40\FSharp.Collections.ParallelSeq.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="FSharp.Core, Version=$(TargetFSharpCoreVersion), Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Collections.ParallelSeq" version="1.0.2" targetFramework="net46" />
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,59 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PersistentDataStructures
|
||||||
|
{
|
||||||
|
// Listing 3.16 Immutable B-tree representation in C#
|
||||||
|
public class BinaryTree<T>
|
||||||
|
{
|
||||||
|
public BinaryTree(T value, BinaryTree<T> left, BinaryTree<T> right)
|
||||||
|
{
|
||||||
|
Value = value;
|
||||||
|
Left = left;
|
||||||
|
Right = right;
|
||||||
|
}
|
||||||
|
public T Value { get; }
|
||||||
|
public BinaryTree<T> Left { get; }
|
||||||
|
public BinaryTree<T> Right { get; }
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class BinaryTreeExtension
|
||||||
|
{
|
||||||
|
// Listing 3.17 B-tree helper recursive functions
|
||||||
|
public static bool Contains<T>(this BinaryTree<T> tree, T value)
|
||||||
|
{
|
||||||
|
if (tree == null) return false;
|
||||||
|
var compare = Comparer<T>.Default.Compare(value, tree.Value);
|
||||||
|
if (compare == 0) return true;
|
||||||
|
if (compare < 0)
|
||||||
|
return tree.Left != null && tree.Left.Contains(value);
|
||||||
|
return tree.Right != null && tree.Right.Contains(value);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static BinaryTree<T> Insert<T>(this BinaryTree<T> tree, T value)
|
||||||
|
{
|
||||||
|
if (tree == null)
|
||||||
|
return new BinaryTree<T>(value, null, null);
|
||||||
|
var compare = Comparer<T>.Default.Compare(value, tree.Value);
|
||||||
|
if (compare == 0) return tree;
|
||||||
|
if (compare < 0)
|
||||||
|
return new BinaryTree<T>(tree.Value,
|
||||||
|
tree.Left.Insert(value), tree.Right);
|
||||||
|
return new BinaryTree<T>(tree.Value,
|
||||||
|
tree.Left, tree.Right.Insert(value));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listing 3.18 In-Order navigation function
|
||||||
|
public static void InOrder<T>(this BinaryTree<T> tree, Action<T> action)
|
||||||
|
{
|
||||||
|
if (tree == null)
|
||||||
|
return;
|
||||||
|
tree.Left.InOrder(action);
|
||||||
|
action(tree.Value);
|
||||||
|
tree.Right.InOrder(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PersistentDataStructures
|
||||||
|
{
|
||||||
|
// Listing 3.14 A functional list in C#
|
||||||
|
public sealed class FList<T>
|
||||||
|
{
|
||||||
|
private FList(T head, FList<T> tail)//#A
|
||||||
|
{
|
||||||
|
Head = head;
|
||||||
|
Tail = tail.IsEmpty
|
||||||
|
? FList<T>.Empty : tail;
|
||||||
|
IsEmpty = false;
|
||||||
|
}
|
||||||
|
private FList() { //#B
|
||||||
|
IsEmpty = true;
|
||||||
|
}
|
||||||
|
public T Head { get; } //#C
|
||||||
|
public FList<T> Tail { get; } //#D
|
||||||
|
public bool IsEmpty { get; } //#E
|
||||||
|
public static FList<T> Cons(T head, FList<T> tail) //#F
|
||||||
|
{
|
||||||
|
return tail.IsEmpty
|
||||||
|
? new FList<T>(head, Empty)
|
||||||
|
: new FList<T>(head, tail);
|
||||||
|
}
|
||||||
|
public FList<T> Cons(T element) //#G
|
||||||
|
{
|
||||||
|
return FList<T>.Cons(element, this);
|
||||||
|
}
|
||||||
|
public static readonly FList<T> Empty = new FList<T>(); //#H
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class FListExtensions
|
||||||
|
{
|
||||||
|
public static FList<TOut> Select<TIn,TOut>
|
||||||
|
(this FList<TIn> list, Func<TIn, TOut> selector)
|
||||||
|
{
|
||||||
|
return list.IsEmpty
|
||||||
|
? FList<TOut>.Empty
|
||||||
|
: list.Tail.Select<TIn, TOut>(selector).Cons(selector(list.Head));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static FList<T> Where<T>
|
||||||
|
(this FList<T> list, Func<T, bool> predicate)
|
||||||
|
{
|
||||||
|
if (list.IsEmpty) return list;
|
||||||
|
var newTail = list.Tail.Where(predicate);
|
||||||
|
return predicate(list.Head)
|
||||||
|
? newTail.Cons(list.Head)
|
||||||
|
: newTail;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{8FB29F53-63C2-44B7-BC08-49A24A055E06}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>PersistentDataStructures</RootNamespace>
|
||||||
|
<AssemblyName>PersistentDataStructures</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Collections.Immutable, Version=1.2.1.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\System.Collections.Immutable.1.3.1\lib\portable-net45+win8+wp8+wpa81\System.Collections.Immutable.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="..\..\Common\Functional.cs\Concurrency\Atom.cs">
|
||||||
|
<Link>Atom.cs</Link>
|
||||||
|
</Compile>
|
||||||
|
<Compile Include="BinaryTree.cs" />
|
||||||
|
<Compile Include="FList.cs" />
|
||||||
|
<Compile Include="LazyList.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Functional.cs\Functional.cs.csproj">
|
||||||
|
<Project>{24d84c19-b173-4635-91a6-42328bc694ce}</Project>
|
||||||
|
<Name>Functional.cs</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
<Choose>
|
||||||
|
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1' Or $(TargetFrameworkVersion) == 'v4.6.2' Or $(TargetFrameworkVersion) == 'v4.6.3')" />
|
||||||
|
</Choose>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="$(TargetFrameworkIdentifier) == '.NETFramework' And ($(TargetFrameworkVersion) == 'v4.5.2' Or $(TargetFrameworkVersion) == 'v4.5.3' Or $(TargetFrameworkVersion) == 'v4.6' Or $(TargetFrameworkVersion) == 'v4.6.1' Or $(TargetFrameworkVersion) == 'v4.6.2' Or $(TargetFrameworkVersion) == 'v4.6.3')">
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="System.Collections.Immutable">
|
||||||
|
<HintPath>..\..\..\packages\System.Collections.Immutable\lib\netstandard1.0\System.Collections.Immutable.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
<Paket>True</Paket>
|
||||||
|
</Reference>
|
||||||
|
</ItemGroup>
|
||||||
|
</When>
|
||||||
|
</Choose>
|
||||||
|
</Project>
|
|
@ -0,0 +1,50 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PersistentDataStructures
|
||||||
|
{
|
||||||
|
// Listing 3.15 Lazy list implementation using C#
|
||||||
|
public sealed class LazyList<T>
|
||||||
|
{
|
||||||
|
public LazyList(T head, Lazy<LazyList<T>> tail)
|
||||||
|
{
|
||||||
|
Head = head;
|
||||||
|
Tail = tail;
|
||||||
|
IsEmpty = false;
|
||||||
|
}
|
||||||
|
private LazyList()
|
||||||
|
{
|
||||||
|
IsEmpty = true;
|
||||||
|
}
|
||||||
|
public T Head { get; }
|
||||||
|
public Lazy<LazyList<T>> Tail { get; }
|
||||||
|
public bool IsEmpty { get; }
|
||||||
|
|
||||||
|
public static readonly Lazy<LazyList<T>> Empty =
|
||||||
|
new Lazy<LazyList<T>>(() => new LazyList<T>());
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class LazyListExtensions
|
||||||
|
{
|
||||||
|
public static LazyList<T> Append<T>
|
||||||
|
(this LazyList<T> list, LazyList<T> items)
|
||||||
|
{
|
||||||
|
if (items.IsEmpty) return list;
|
||||||
|
return new LazyList<T>(items.Head,
|
||||||
|
new Lazy<LazyList<T>>(() =>
|
||||||
|
list.Append(items.Tail.Value)));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void Iterate<T>
|
||||||
|
(this LazyList<T> list, Action<T> action)
|
||||||
|
{
|
||||||
|
if (list.IsEmpty)
|
||||||
|
return;
|
||||||
|
action(list.Head);
|
||||||
|
list.Tail.Value.Iterate(action);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
|
||||||
|
namespace PersistentDataStructures
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
// Listing 3.1 SignalR hub in C# that registers connections in context
|
||||||
|
class Listing31
|
||||||
|
{
|
||||||
|
static ConcurrentDictionary<Guid, string> onlineUsers = new ConcurrentDictionary<Guid, string>(); //#A
|
||||||
|
|
||||||
|
// public override Task OnConnected()
|
||||||
|
// {
|
||||||
|
// string connectionId = new Guid(Context.ConnectionId); //#B
|
||||||
|
// System.Security.Principal.IPrincipal user = Context.User;
|
||||||
|
// string userName;
|
||||||
|
// if (!onlineUsers.TryGetValue(connectionId, out userName))
|
||||||
|
// { //#C
|
||||||
|
// RegisterUserConnection(connectionId, user.Identity.Name);
|
||||||
|
// onlineUsers.Add(connectionId, user.Identity.Name); //#D
|
||||||
|
// }
|
||||||
|
// return base.OnConnected();
|
||||||
|
// }
|
||||||
|
// public override Task OnDisconnected()
|
||||||
|
// {
|
||||||
|
// string connectionId = new Guid(Context.ConnectionId);
|
||||||
|
// string userName;
|
||||||
|
// if (onlineUsers.TryGetValue(connectionId, out userName))
|
||||||
|
// { //#C
|
||||||
|
// DeregisterUserConnection(connectionId, userName);
|
||||||
|
// onlineUsers.Remove(connectionId); //#D
|
||||||
|
// }
|
||||||
|
// return base.OnDisconnected();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
// Listing 3.2 Constructing BCL immutable collections
|
||||||
|
var list = ImmutableList.Create<int>(); //#A
|
||||||
|
list = list.Add(1); //#B
|
||||||
|
list = list.Add(2);
|
||||||
|
list = list.Add(3);
|
||||||
|
|
||||||
|
var builder = ImmutableList.CreateBuilder<int>(); //#C
|
||||||
|
builder.Add(1); //#D
|
||||||
|
builder.Add(2);
|
||||||
|
builder.Add(3);
|
||||||
|
list = builder.ToImmutable(); //#E
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 3.14 A functional list in C#
|
||||||
|
FList<int> list1 = FList<int>.Empty;
|
||||||
|
FList<int> list2 = list1.Cons(1).Cons(2).Cons(3);
|
||||||
|
FList<int> list3 = FList<int>.Cons(1, FList<int>.Empty);
|
||||||
|
FList<int> list4 = list2.Cons(2).Cons(3);
|
||||||
|
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
Console.WriteLine("Listing 3.15 Lazy list implementation");
|
||||||
|
var lazyList1 =
|
||||||
|
new LazyList<int>(42, new Lazy<LazyList<int>>(()=>
|
||||||
|
new LazyList<int>(21, LazyList<int>.Empty)));
|
||||||
|
var lazyList =
|
||||||
|
lazyList1.Append(
|
||||||
|
new LazyList<int>(3, LazyList<int>.Empty));
|
||||||
|
lazyList.Iterate(Console.WriteLine);
|
||||||
|
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
|
||||||
|
Console.WriteLine("Listing 3.16 Immutable B-tree representation");
|
||||||
|
var tree =
|
||||||
|
new BinaryTree<int>(20,
|
||||||
|
new BinaryTree<int>(9,
|
||||||
|
new BinaryTree<int>(4,
|
||||||
|
new BinaryTree<int>(2, null, null),
|
||||||
|
null),
|
||||||
|
new BinaryTree<int>(10, null, null)),
|
||||||
|
null);
|
||||||
|
|
||||||
|
var exist9 = tree.Contains(9);
|
||||||
|
Console.WriteLine($"Tree contains 9 : {exist9}");
|
||||||
|
var tree21 = tree.Insert(21);
|
||||||
|
var exist21 = tree21.Contains(21);
|
||||||
|
Console.WriteLine($"Tree21 contains 21 : {exist21}\n");
|
||||||
|
|
||||||
|
tree.InOrder(Console.WriteLine);
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup><supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" /></startup>
|
||||||
|
<runtime>
|
||||||
|
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Linq" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
<dependentAssembly>
|
||||||
|
<assemblyIdentity name="System.Runtime.Extensions" publicKeyToken="b03f5f7f11d50a3a" culture="neutral" />
|
||||||
|
<bindingRedirect oldVersion="0.0.0.0-4.1.0.0" newVersion="4.1.0.0" />
|
||||||
|
</dependentAssembly>
|
||||||
|
</assemblyBinding>
|
||||||
|
</runtime>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="System.Collections.Immutable" version="1.3.1" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,26 @@
|
||||||
|
module Atom
|
||||||
|
|
||||||
|
open System.Threading
|
||||||
|
|
||||||
|
let eq a b = obj.ReferenceEquals(a,b)
|
||||||
|
let neq a b = eq a b |> not
|
||||||
|
|
||||||
|
type Atom<'T when 'T : not struct>(value : 'T) =
|
||||||
|
let cell = ref value
|
||||||
|
let spinner = lazy (new SpinWait())
|
||||||
|
|
||||||
|
let rec swap f =
|
||||||
|
let tempValue = !cell
|
||||||
|
if Interlocked.CompareExchange<'T>(cell, f tempValue, tempValue) |> neq tempValue then
|
||||||
|
spinner.Value.SpinOnce()
|
||||||
|
swap f
|
||||||
|
|
||||||
|
|
||||||
|
member x.Value with get() = !cell
|
||||||
|
member x.Swap (f : 'T -> 'T) = swap f
|
||||||
|
|
||||||
|
[<RequireQualifiedAccess>]
|
||||||
|
module Atom =
|
||||||
|
let atom value = new Atom<_>(value)
|
||||||
|
|
||||||
|
let swap (atom : Atom<_>) (f : _ -> _) = atom.Swap f
|
|
@ -0,0 +1,46 @@
|
||||||
|
module BTree
|
||||||
|
|
||||||
|
// Listing 3.16 Immutable B-tree representation in F#
|
||||||
|
type Tree<'a> = //#A
|
||||||
|
| Empty //#B
|
||||||
|
| Node of leaf:'a * left:Tree<'a> * right:Tree<'a> //#C
|
||||||
|
|
||||||
|
let tree = //#D
|
||||||
|
Node (20,
|
||||||
|
Node (9, Node (4, Node (2, Empty, Empty), Empty),
|
||||||
|
Node (10, Empty, Empty)),
|
||||||
|
Empty)
|
||||||
|
|
||||||
|
// Listing 3.17 B-tree helper recursive functions
|
||||||
|
let rec contains item tree = //#A
|
||||||
|
match tree with
|
||||||
|
| Empty -> false
|
||||||
|
| Node(leaf, left, right) ->
|
||||||
|
if leaf = item then true
|
||||||
|
elif item < leaf then contains item left
|
||||||
|
else contains item right
|
||||||
|
|
||||||
|
let rec insert item tree = //#A
|
||||||
|
match tree with
|
||||||
|
| Empty -> Node(item, Empty, Empty)
|
||||||
|
| Node(leaf, left, right) as node ->
|
||||||
|
if leaf = item then node
|
||||||
|
elif item < leaf then Node(leaf, insert item left, right)
|
||||||
|
else Node(leaf, left, insert item right)
|
||||||
|
|
||||||
|
let ``exist 9`` = tree |> contains 9
|
||||||
|
let ``tree 21`` = tree |> insert 21
|
||||||
|
let ``exist 21`` = ``tree 21`` |> contains 21
|
||||||
|
|
||||||
|
// Listing 3.18 In-Order navigation function
|
||||||
|
let rec inorder action tree = //#A
|
||||||
|
seq {
|
||||||
|
match tree with
|
||||||
|
| Node(leaf, left, right) ->
|
||||||
|
yield! inorder action left
|
||||||
|
yield action leaf
|
||||||
|
yield! inorder action right
|
||||||
|
| Empty -> ()
|
||||||
|
}
|
||||||
|
|
||||||
|
tree |> inorder (fun n -> printfn "%d" n) |> ignore //#B
|
|
@ -0,0 +1,19 @@
|
||||||
|
module FList
|
||||||
|
|
||||||
|
// Listing 3.13 Representation of a list in F# using discriminated unions
|
||||||
|
type FList<'a> =
|
||||||
|
| Empty //#A
|
||||||
|
| Cons of head:'a * tail:FList<'a> //#B
|
||||||
|
|
||||||
|
let rec map f (list:FList<'a>) = //#C
|
||||||
|
match list with
|
||||||
|
| Empty -> Empty
|
||||||
|
| Cons(hd,tl) -> Cons(f hd, map f tl)
|
||||||
|
|
||||||
|
let rec filter p (list:FList<'a>) =
|
||||||
|
match list with
|
||||||
|
| Empty -> Empty
|
||||||
|
| Cons(hd,tl) when p hd = true -> Cons(hd, filter p tl)
|
||||||
|
| Cons(hd,tl) -> filter p tl
|
||||||
|
|
||||||
|
let list = Cons(5, Cons(4, Cons(3, Empty)))
|
|
@ -0,0 +1,90 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>832224d4-d636-430f-ab7f-fcb02603be51</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>DataStructures</RootNamespace>
|
||||||
|
<AssemblyName>DataStructures</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFSharpCoreVersion>4.4.3.0</TargetFSharpCoreVersion>
|
||||||
|
<Name>FunctionalDataStructures.fs</Name>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Debug\DataStructures.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Release\DataStructures.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Atom.fs" />
|
||||||
|
<Compile Include="FList.fs" />
|
||||||
|
<Compile Include="LazyList.fs" />
|
||||||
|
<Compile Include="BTree.fs" />
|
||||||
|
<Compile Include="ParallelDownloadImages.fs" />
|
||||||
|
<Compile Include="WeakMemoization.fs" />
|
||||||
|
<Compile Include="TCO_CPS.fs" />
|
||||||
|
<Compile Include="ParallelCalculator.fs" />
|
||||||
|
<None Include="App.config" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<ProjectReference Include="..\..\Chapter.02\FunctionalTechniques.cs\FunctionalTechniques.cs.csproj">
|
||||||
|
<Name>FunctionalTechniques.cs</Name>
|
||||||
|
<Project>{22d90ff3-0f4d-468b-aba1-1cd6a82d16da}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,29 @@
|
||||||
|
module LazyList
|
||||||
|
|
||||||
|
// Listing 3.15 Lazy list implementation using F#
|
||||||
|
type LazyList<'a> =
|
||||||
|
| Cons of head:'a * tail:Lazy<'a LazyList> //#A
|
||||||
|
| Empty
|
||||||
|
let empty = lazy(Empty) //#B
|
||||||
|
|
||||||
|
let rec append items list = //#C
|
||||||
|
match items with
|
||||||
|
| Cons(head, Lazy(tail)) ->
|
||||||
|
Cons(head, lazy(append tail list)) //#D
|
||||||
|
| Empty -> list
|
||||||
|
|
||||||
|
let list1 = Cons(42, lazy(Cons(21, empty))) //#E
|
||||||
|
// val list1: LazyList<int> = Cons (42,Value is not created.)
|
||||||
|
|
||||||
|
let list = append (Cons(3, empty)) list1 //#F
|
||||||
|
// val list : LazyList<int> = Cons (3,Value is not created.)
|
||||||
|
|
||||||
|
let rec iter action list = //#G
|
||||||
|
match list with
|
||||||
|
| Cons(head, Lazy(tail)) ->
|
||||||
|
action(head)
|
||||||
|
iter action tail
|
||||||
|
| Empty -> ()
|
||||||
|
|
||||||
|
list |> iter (printf "%d .. ") //#H
|
||||||
|
// 3 .. 42 .. 21 ..
|
|
@ -0,0 +1,37 @@
|
||||||
|
module ParallelCalculator
|
||||||
|
|
||||||
|
open System.Threading.Tasks
|
||||||
|
|
||||||
|
// Listing 3.23 Parallel Calculator
|
||||||
|
type Operation = Add | Sub | Mul | Div | Pow
|
||||||
|
|
||||||
|
and Calculator =
|
||||||
|
| Value of double
|
||||||
|
| Expr of Operation * Calculator * Calculator
|
||||||
|
|
||||||
|
let spawn (op:unit->double) = Task.Run(op) //#A
|
||||||
|
|
||||||
|
let rec eval expr =
|
||||||
|
match expr with //#B
|
||||||
|
| Value(value) -> value //#C
|
||||||
|
| Expr(op, lExpr, rExpr) -> //#D
|
||||||
|
let op1 = spawn(fun () -> eval lExpr) //#E
|
||||||
|
let op2 = spawn(fun () -> eval rExpr) //#E
|
||||||
|
let apply = Task.WhenAll([op1;op2]) //#F
|
||||||
|
let lRes, rRes = apply.Result.[0], apply.Result.[1]
|
||||||
|
match op with //#G
|
||||||
|
| Add -> lRes + rRes
|
||||||
|
| Sub -> lRes - rRes
|
||||||
|
| Mul -> lRes * rRes
|
||||||
|
| Div -> lRes / rRes
|
||||||
|
| Pow -> System.Math.Pow(lRes, rRes)
|
||||||
|
|
||||||
|
|
||||||
|
let operations = // 2^10 / 2^9 + 2*2
|
||||||
|
Expr(Add,
|
||||||
|
Expr(Div,
|
||||||
|
Expr(Pow, Value(2.0), Value(10.0)),
|
||||||
|
Expr(Pow, Value(2.0), Value(9.0))),
|
||||||
|
Expr(Mul, Value(2.0), Value(2.0)))
|
||||||
|
|
||||||
|
let value = eval operations
|
|
@ -0,0 +1,32 @@
|
||||||
|
module ParallelDownloadImages
|
||||||
|
|
||||||
|
open BTree
|
||||||
|
open FunctionalTechniques.cs
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open System.Threading.Tasks
|
||||||
|
|
||||||
|
//Listing 3.22 Parallel recursive divide-and-conquer function
|
||||||
|
let maxDepth = int <| Math.Log(float System.Environment.ProcessorCount, 2.)+4. //#A
|
||||||
|
|
||||||
|
let webSites : Tree<string> =
|
||||||
|
WebCrawlerExample.WebCrawler("http://www.foxnews.com")
|
||||||
|
|> Seq.fold(fun tree site -> insert site tree ) Empty //#B
|
||||||
|
|
||||||
|
let downloadImage (url:string) =
|
||||||
|
use client = new System.Net.WebClient()
|
||||||
|
let fileName = Path.GetFileName(url)
|
||||||
|
client.DownloadFile(url, @"c:\Images\" + fileName) //#C
|
||||||
|
|
||||||
|
let rec parallelDownloadImages tree depth = //#D
|
||||||
|
match tree with
|
||||||
|
| _ when depth = maxDepth ->
|
||||||
|
tree |> inorder downloadImage |> ignore
|
||||||
|
| Node(leaf, left, right) ->
|
||||||
|
let taskLeft = Task.Run(fun() ->
|
||||||
|
parallelDownloadImages left (depth + 1))
|
||||||
|
let taskRight = Task.Run(fun() ->
|
||||||
|
parallelDownloadImages right (depth + 1))
|
||||||
|
let taskLeaf = Task.Run(fun() -> downloadImage leaf)
|
||||||
|
Task.WaitAll([|taskLeft;taskRight;taskLeaf|]) //#E
|
||||||
|
| Empty -> ()
|
|
@ -0,0 +1,17 @@
|
||||||
|
module TCO_CPS
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 3.19 Tail recursive implementation of factorial in F#
|
||||||
|
let rec factorialTCO (n:int) (acc:int) =
|
||||||
|
if n <= 1 then acc
|
||||||
|
else factorialTCO (n-1) (acc * n) //#A
|
||||||
|
|
||||||
|
let factorial n = factorialTCO n 1
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 3.21 Recursive implementation of factorial using CPS
|
||||||
|
let rec factorialCPS x continuation =
|
||||||
|
if x <= 1 then continuation()
|
||||||
|
else factorialCPS (x - 1) (fun () -> x * continuation())
|
||||||
|
|
||||||
|
let result = factorialCPS 4 (fun () -> 1) //#A
|
|
@ -0,0 +1,46 @@
|
||||||
|
module WeakMemoization
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Collections.Concurrent
|
||||||
|
open System.Runtime.CompilerServices
|
||||||
|
|
||||||
|
|
||||||
|
let memoizeWeakWithTtl (func :'a->'b) ttl =
|
||||||
|
let keyStore = ConcurrentDictionary<int, 'a>()
|
||||||
|
let reduceKey (obj: 'a) =
|
||||||
|
let oldObj = keyStore.GetOrAdd(obj.GetHashCode(), obj)
|
||||||
|
if obj.Equals(oldObj) then oldObj else obj
|
||||||
|
|
||||||
|
let cache = ConditionalWeakTable<'a, 'b * DateTime>()
|
||||||
|
let factoryFunc =
|
||||||
|
ConditionalWeakTable<'a, 'b * DateTime>
|
||||||
|
.CreateValueCallback(
|
||||||
|
fun key -> func key, DateTime.Now + ttl)
|
||||||
|
|
||||||
|
fun (arg:'a) ->
|
||||||
|
let key = reduceKey arg
|
||||||
|
|
||||||
|
let (value, due) = cache.GetValue(key, factoryFunc)
|
||||||
|
if (due < DateTime.Now)
|
||||||
|
then
|
||||||
|
let newValue = factoryFunc.Invoke(key)
|
||||||
|
cache.Remove(key) |> ignore
|
||||||
|
cache.Add(key, newValue)
|
||||||
|
fst newValue
|
||||||
|
else value
|
||||||
|
|
||||||
|
|
||||||
|
let example() =
|
||||||
|
let greating name =
|
||||||
|
sprintf "Warm greetings %s, the time is %s"
|
||||||
|
name (DateTime.Now.ToString("hh:mm:ss"))
|
||||||
|
|
||||||
|
let greetingMemoize =
|
||||||
|
memoizeWeakWithTtl greating (TimeSpan.FromSeconds(2.0))
|
||||||
|
|
||||||
|
printfn "%s" <| greetingMemoize("Richard")
|
||||||
|
System.Threading.Thread.Sleep(1500)
|
||||||
|
printfn "%s" <| greetingMemoize("_Richard".Substring(1))
|
||||||
|
System.Threading.Thread.Sleep(1500)
|
||||||
|
printfn "%s" <| greetingMemoize("_Richard".Substring(1))
|
||||||
|
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7"/>
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,28 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.cs
|
||||||
|
{
|
||||||
|
public static class ArraySum
|
||||||
|
{
|
||||||
|
public static int SequentialSum(int[] data)
|
||||||
|
{
|
||||||
|
//Listing 4.6 Common For loop
|
||||||
|
int sum = 0;
|
||||||
|
for (int i = 0; i < data.Length; i++)
|
||||||
|
{
|
||||||
|
sum += data[i]; //#A
|
||||||
|
}
|
||||||
|
return sum;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static int SequentialSumLINQ(int[] data)
|
||||||
|
{
|
||||||
|
return data.Sum();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.cs
|
||||||
|
{
|
||||||
|
// Listing 4.1 Complex number object
|
||||||
|
class Complex
|
||||||
|
{
|
||||||
|
public Complex(float real, float imaginary)
|
||||||
|
{
|
||||||
|
Real = real;
|
||||||
|
Imaginary = imaginary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Imaginary { get; } //#A
|
||||||
|
public float Real { get; } //#A
|
||||||
|
|
||||||
|
public float Magnitude
|
||||||
|
=> (float)Math.Sqrt(Real * Real + Imaginary * Imaginary); //#B
|
||||||
|
|
||||||
|
public static Complex operator +(Complex c1, Complex c2)
|
||||||
|
=> new Complex(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary); //#C
|
||||||
|
public static Complex operator *(Complex c1, Complex c2)
|
||||||
|
=> new Complex(c1.Real * c2.Real - c1.Imaginary * c2.Imaginary,
|
||||||
|
c1.Real * c2.Imaginary + c1.Imaginary * c2.Real); //#C
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ComplexStruct
|
||||||
|
{
|
||||||
|
public ComplexStruct(float real, float imaginary)
|
||||||
|
{
|
||||||
|
Real = real;
|
||||||
|
Imaginary = imaginary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public float Imaginary { get; }
|
||||||
|
public float Real { get; }
|
||||||
|
|
||||||
|
public float Magnitude
|
||||||
|
=> (float)Math.Sqrt(Real * Real + Imaginary * Imaginary);
|
||||||
|
|
||||||
|
public static ComplexStruct operator +(ComplexStruct c1, ComplexStruct c2)
|
||||||
|
=> new ComplexStruct(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary);
|
||||||
|
|
||||||
|
public static ComplexStruct operator *(ComplexStruct c1, ComplexStruct c2)
|
||||||
|
=> new ComplexStruct(c1.Real * c2.Real - c1.Imaginary * c2.Imaginary,
|
||||||
|
c1.Real * c2.Imaginary + c1.Imaginary * c2.Real);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{B3777684-C6FA-4011-AC1B-04C810E11F14}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>DataParallelism.cs</RootNamespace>
|
||||||
|
<AssemblyName>DataParallelism.cs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="ArraySum.cs" />
|
||||||
|
<Compile Include="Complex.cs" />
|
||||||
|
<Compile Include="Mandelbrot.cs" />
|
||||||
|
<Compile Include="PrimeNumbers.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="App.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,211 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Drawing.Imaging;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.cs
|
||||||
|
{
|
||||||
|
public class Mandelbrot
|
||||||
|
{
|
||||||
|
private const int Rows = 2000;
|
||||||
|
private const int Cols = 2000;
|
||||||
|
private static readonly Complex Center = new Complex(-0.75f, 0.0f);
|
||||||
|
|
||||||
|
private const float Width = 2.5f;
|
||||||
|
private const float Height = 2.5f;
|
||||||
|
|
||||||
|
private static float ComputeRow(int col)
|
||||||
|
=> Center.Real - Width / 2.0f + (float)col * Width / (float)Cols;
|
||||||
|
|
||||||
|
private static float ComputeColumn(int row)
|
||||||
|
=> Center.Imaginary - Height / 2.0f + (float)row * Height / (float)Rows;
|
||||||
|
|
||||||
|
public static Bitmap SequentialMandelbrot()
|
||||||
|
{
|
||||||
|
var bitmap = new Bitmap(Rows, Cols, PixelFormat.Format24bppRgb);
|
||||||
|
var bitmapData =
|
||||||
|
bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||||
|
var pixels = new byte[bitmapData.Stride * bitmap.Height];
|
||||||
|
var ptrFirstPixel = bitmapData.Scan0;
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
|
||||||
|
|
||||||
|
// Listing 4.2 Sequential Mandelbrot
|
||||||
|
Func<Complex, int, bool> isMandelbrot = (complex, iterations) => //#A
|
||||||
|
{
|
||||||
|
var z = new Complex(0.0f, 0.0f);
|
||||||
|
int acc = 0;
|
||||||
|
while (acc < iterations && z.Magnitude < 2.0)
|
||||||
|
{
|
||||||
|
z = z * z + complex;
|
||||||
|
acc += 1;
|
||||||
|
}
|
||||||
|
return acc == iterations;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (int col = 0; col < Cols; col++) //#B
|
||||||
|
{
|
||||||
|
for (int row = 0; row < Rows; row++) //#B
|
||||||
|
{
|
||||||
|
var x = ComputeRow(row); //#C
|
||||||
|
var y = ComputeColumn(col); //#C
|
||||||
|
var c = new Complex(x, y);
|
||||||
|
var color = isMandelbrot(c, 100) ? Color.Black : Color.White; //#D
|
||||||
|
var offset = (col * bitmapData.Stride) + (3 * row);
|
||||||
|
pixels[offset + 0] = color.B; // Blue component //#E
|
||||||
|
pixels[offset + 1] = color.G; // Green component //#E
|
||||||
|
pixels[offset + 2] = color.R; // Red component //#E
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
|
||||||
|
var image = (Bitmap)bitmap.Clone();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap ParallelMandelbrot()
|
||||||
|
{
|
||||||
|
|
||||||
|
var bitmap = new Bitmap(Rows, Cols, PixelFormat.Format24bppRgb);
|
||||||
|
var bitmapData =
|
||||||
|
bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||||
|
var pixels = new byte[bitmapData.Stride * bitmap.Height];
|
||||||
|
var ptrFirstPixel = bitmapData.Scan0;
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
|
||||||
|
|
||||||
|
// Listing 4.3 Parallel Mandelbrot
|
||||||
|
Func<Complex, int, bool> isMandelbrot = (complex, iterations) =>
|
||||||
|
{
|
||||||
|
var z = new Complex(0.0f, 0.0f);
|
||||||
|
int acc = 0;
|
||||||
|
while (acc < iterations && z.Magnitude < 2.0)
|
||||||
|
{
|
||||||
|
z = z * z + complex;
|
||||||
|
acc += 1;
|
||||||
|
}
|
||||||
|
return acc == iterations;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parallel.For(0, Cols - 1, col =>
|
||||||
|
{ //#A
|
||||||
|
for (int row = 0; row < Rows; row++)
|
||||||
|
{
|
||||||
|
var x = ComputeRow(row);
|
||||||
|
var y = ComputeColumn(col);
|
||||||
|
var c = new Complex(x, y);
|
||||||
|
var color = isMandelbrot(c, 100) ? Color.DarkBlue : Color.White;
|
||||||
|
var offset = (col * bitmapData.Stride) + (3 * row);
|
||||||
|
pixels[offset + 0] = color.B; // Blue component
|
||||||
|
pixels[offset + 1] = color.G; // Green component
|
||||||
|
pixels[offset + 2] = color.R; // Red component
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
var image = (Bitmap)bitmap.Clone();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Bitmap ParallelMandelbrotOversaturation()
|
||||||
|
{
|
||||||
|
var bitmap = new Bitmap(Rows, Cols, PixelFormat.Format24bppRgb);
|
||||||
|
var bitmapData =
|
||||||
|
bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||||
|
var pixels = new byte[bitmapData.Stride * bitmap.Height];
|
||||||
|
var ptrFirstPixel = bitmapData.Scan0;
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
|
||||||
|
|
||||||
|
Func<Complex, int, bool> isMandelbrot = (complex, iterations) =>
|
||||||
|
{
|
||||||
|
var z = new Complex(0.0f, 0.0f);
|
||||||
|
int acc = 0;
|
||||||
|
while (acc < iterations && z.Magnitude < 2.0)
|
||||||
|
{
|
||||||
|
z = z * z + complex;
|
||||||
|
acc += 1;
|
||||||
|
}
|
||||||
|
return acc == iterations;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parallel.For(0, Cols - 1, col =>
|
||||||
|
{
|
||||||
|
Parallel.For(0, Rows - 1, row =>
|
||||||
|
{
|
||||||
|
var x = ComputeRow(row);
|
||||||
|
var y = ComputeColumn(col);
|
||||||
|
var c = new Complex(x, y);
|
||||||
|
var color = isMandelbrot(c, 100) ? Color.DarkBlue : Color.White;
|
||||||
|
var offset = (col * bitmapData.Stride) + (3 * row);
|
||||||
|
pixels[offset + 0] = color.B; // Blue component
|
||||||
|
pixels[offset + 1] = color.G; // Green component
|
||||||
|
pixels[offset + 2] = color.R; // Red component
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
var image = (Bitmap)bitmap.Clone();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static ComplexStruct _centerStruct = new ComplexStruct(-0.75f, 0.0f);
|
||||||
|
|
||||||
|
private static float ComputeRowStruct(int col)
|
||||||
|
=> _centerStruct.Real - Width / 2.0f + (float)col * Width / (float)Cols;
|
||||||
|
|
||||||
|
private static float ComputeColumnStruct(int row)
|
||||||
|
=> _centerStruct.Imaginary - Height / 2.0f + (float)row * Height / (float)Rows;
|
||||||
|
|
||||||
|
public static Bitmap ParallelStructMandelbrot()
|
||||||
|
{
|
||||||
|
var bitmap = new Bitmap(Rows, Cols, PixelFormat.Format24bppRgb);
|
||||||
|
var bitmapData =
|
||||||
|
bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
|
||||||
|
var pixels = new byte[bitmapData.Stride * bitmap.Height];
|
||||||
|
var ptrFirstPixel = bitmapData.Scan0;
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length);
|
||||||
|
|
||||||
|
Func<ComplexStruct, int, bool> isMandelbrot = (complex, iterations) =>
|
||||||
|
{
|
||||||
|
var z = new ComplexStruct(0.0f, 0.0f);
|
||||||
|
int acc = 0;
|
||||||
|
while (acc < iterations && z.Magnitude < 2.0)
|
||||||
|
{
|
||||||
|
z = z * z + complex;
|
||||||
|
acc += 1;
|
||||||
|
}
|
||||||
|
return acc == iterations;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parallel.For(0, Cols - 1, col =>
|
||||||
|
{
|
||||||
|
for (int row = 0; row < Rows; row++)
|
||||||
|
{
|
||||||
|
var x = ComputeRowStruct(row);
|
||||||
|
var y = ComputeColumnStruct(col);
|
||||||
|
var c = new ComplexStruct(x, y);
|
||||||
|
var color = isMandelbrot(c, 100) ? Color.DarkBlue : Color.White;
|
||||||
|
var offset = (col * bitmapData.Stride) + (3 * row);
|
||||||
|
pixels[offset + 0] = color.B; // Blue component
|
||||||
|
pixels[offset + 1] = color.G; // Green component
|
||||||
|
pixels[offset + 2] = color.R; // Red component
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length);
|
||||||
|
bitmap.UnlockBits(bitmapData);
|
||||||
|
var image = (Bitmap)bitmap.Clone();
|
||||||
|
return image;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,100 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.cs
|
||||||
|
{
|
||||||
|
public static class PrimeNumbers
|
||||||
|
{
|
||||||
|
public static long PrimeSumSequential()
|
||||||
|
{
|
||||||
|
int len = 10000000;
|
||||||
|
long total = 0;
|
||||||
|
Func<int, bool> isPrime = n =>
|
||||||
|
{
|
||||||
|
if (n == 1) return false;
|
||||||
|
if (n == 2) return true;
|
||||||
|
var boundary = (int)Math.Floor(Math.Sqrt(n));
|
||||||
|
for (int i = 2; i <= boundary; ++i)
|
||||||
|
if (n % i == 0) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
for (var i=1; i<=len; ++i)
|
||||||
|
{
|
||||||
|
if (isPrime(i))
|
||||||
|
total += i;
|
||||||
|
}
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long PrimeSumParallel()
|
||||||
|
{
|
||||||
|
// Listing 4.4 Parallel sum of prime numbers in a collection using Parallel.For loop construct
|
||||||
|
int len = 10000000;
|
||||||
|
long total = 0; //#A
|
||||||
|
Func<int, bool> isPrime = n => //#B
|
||||||
|
{
|
||||||
|
if (n == 1) return false;
|
||||||
|
if (n == 2) return true;
|
||||||
|
var boundary = (int) Math.Floor(Math.Sqrt(n));
|
||||||
|
for (int i = 2; i <= boundary; ++i)
|
||||||
|
if (n%i == 0) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
Parallel.For(0, len, i => //#C
|
||||||
|
{
|
||||||
|
if (isPrime(i)) //#D
|
||||||
|
total += i; //#D
|
||||||
|
});
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long PrimeSumParallelThreadLocal()
|
||||||
|
{
|
||||||
|
int len = 10000000;
|
||||||
|
long total = 0;
|
||||||
|
Func<int, bool> isPrime = n =>
|
||||||
|
{
|
||||||
|
if (n == 1) return false;
|
||||||
|
if (n == 2) return true;
|
||||||
|
var boundary = (int)Math.Floor(Math.Sqrt(n));
|
||||||
|
for (int i = 2; i <= boundary; ++i)
|
||||||
|
if (n % i == 0) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listing 4.5 Thread-safe parallel sum using Parallel.For and ThreadLocal
|
||||||
|
Parallel.For(0, len,
|
||||||
|
() => 0, //#A
|
||||||
|
(int i, ParallelLoopState loopState, long tlsValue) //#B
|
||||||
|
=> isPrime(i) ? tlsValue += i : tlsValue,
|
||||||
|
value => Interlocked.Add(ref total, value)); //#C
|
||||||
|
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static long PrimeSumParallelLINQ()
|
||||||
|
{
|
||||||
|
int len = 10000000;
|
||||||
|
Func<int, bool> isPrime = n =>
|
||||||
|
{
|
||||||
|
if (n == 1) return false;
|
||||||
|
if (n == 2) return true;
|
||||||
|
var boundary = (int)Math.Floor(Math.Sqrt(n));
|
||||||
|
for (int i = 2; i <= boundary; ++i)
|
||||||
|
if (n % i == 0) return false;
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
|
// Listing 4.7 Parallel sum of a collection using declarative PLINQ
|
||||||
|
long total = Enumerable.Range(0, len).AsParallel().Where(isPrime).Sum(x => (long)x); //#B
|
||||||
|
return total;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,78 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Drawing;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
using System.Windows.Forms;
|
||||||
|
|
||||||
|
namespace DataParallelism.cs
|
||||||
|
{
|
||||||
|
class Program
|
||||||
|
{
|
||||||
|
static void Mandelbrot_Performance_Comparison()
|
||||||
|
{
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
Console.WriteLine("Mandelbrot Performance Comparison");
|
||||||
|
Func<Func<Bitmap>, Action[]> run = (func) =>
|
||||||
|
new Action[] { () => { func(); } };
|
||||||
|
|
||||||
|
var implementations =
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Sequential", run(Mandelbrot.SequentialMandelbrot)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel.For", run(Mandelbrot.ParallelMandelbrot)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel.For Saturated", run(Mandelbrot.ParallelMandelbrotOversaturation)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel.For Struct", run(Mandelbrot.ParallelStructMandelbrot))
|
||||||
|
};
|
||||||
|
|
||||||
|
Application.Run(
|
||||||
|
PerfVis.toChart("C# Mandelbrot")
|
||||||
|
.Invoke(PerfVis.fromTuples(implementations)));
|
||||||
|
}
|
||||||
|
|
||||||
|
static void Prime_Sum()
|
||||||
|
{
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
Console.WriteLine("Prime Sum [0..10^7]");
|
||||||
|
Func<Func<long>, Action[]> runSum = (func) =>
|
||||||
|
new Action[]
|
||||||
|
{
|
||||||
|
() =>
|
||||||
|
{
|
||||||
|
var result = func();
|
||||||
|
Console.WriteLine($"Sum = {result}");
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
var sumImplementations =
|
||||||
|
new[]
|
||||||
|
{
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Sequential", runSum(PrimeNumbers.PrimeSumSequential)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel.For", runSum(PrimeNumbers.PrimeSumParallel)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel.For ThreadLocal", runSum(PrimeNumbers.PrimeSumParallelThreadLocal)),
|
||||||
|
new Tuple<String, Action[]>(
|
||||||
|
"C# Parallel LINQ", runSum(PrimeNumbers.PrimeSumParallelLINQ))
|
||||||
|
};
|
||||||
|
Application.Run(
|
||||||
|
PerfVis.toChart("C# Prime Sum")
|
||||||
|
.Invoke(PerfVis.fromTuples(sumImplementations)));
|
||||||
|
}
|
||||||
|
|
||||||
|
[STAThread]
|
||||||
|
static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Mandelbrot_Performance_Comparison();
|
||||||
|
// Prime_Sum();
|
||||||
|
|
||||||
|
Console.ReadLine();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,4 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,6 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<configuration>
|
||||||
|
<startup>
|
||||||
|
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.7" />
|
||||||
|
</startup>
|
||||||
|
</configuration>
|
|
@ -0,0 +1,93 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<SchemaVersion>2.0</SchemaVersion>
|
||||||
|
<ProjectGuid>80404a98-4757-4a1e-861b-03fcf4fdd4ab</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<RootNamespace>DataParallelism.fs</RootNamespace>
|
||||||
|
<AssemblyName>DataParallelism.fs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<AutoGenerateBindingRedirects>true</AutoGenerateBindingRedirects>
|
||||||
|
<TargetFSharpCoreVersion>4.4.3.0</TargetFSharpCoreVersion>
|
||||||
|
<Name>DataParallelism.Part1.fs</Name>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<Tailcalls>false</Tailcalls>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Debug\DataParallelism.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<Tailcalls>true</Tailcalls>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<WarningLevel>3</WarningLevel>
|
||||||
|
<PlatformTarget>AnyCPU</PlatformTarget>
|
||||||
|
<DocumentationFile>bin\Release\DataParallelism.fs.XML</DocumentationFile>
|
||||||
|
<Prefer32Bit>true</Prefer32Bit>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<MinimumVisualStudioVersion Condition="'$(MinimumVisualStudioVersion)' == ''">11</MinimumVisualStudioVersion>
|
||||||
|
</PropertyGroup>
|
||||||
|
<Choose>
|
||||||
|
<When Condition="'$(VisualStudioVersion)' == '11.0'">
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</When>
|
||||||
|
<Otherwise>
|
||||||
|
<PropertyGroup Condition="Exists('$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets')">
|
||||||
|
<FSharpTargetsPath>$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets</FSharpTargetsPath>
|
||||||
|
</PropertyGroup>
|
||||||
|
</Otherwise>
|
||||||
|
</Choose>
|
||||||
|
<Import Project="$(FSharpTargetsPath)" />
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="Mandelbrot.fs" />
|
||||||
|
<Compile Include="PrimeNumbers.fs" />
|
||||||
|
<Compile Include="Program.fs" />
|
||||||
|
<None Include="App.config" />
|
||||||
|
<Content Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Collections.ParallelSeq">
|
||||||
|
<HintPath>..\..\packages\FSharp.Collections.ParallelSeq.1.0.2\lib\net40\FSharp.Collections.ParallelSeq.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="FSharp.Core">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="mscorlib" />
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Numerics" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Private>True</Private>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,137 @@
|
||||||
|
module Mandelbrot
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.IO
|
||||||
|
open System.Linq
|
||||||
|
open System.Drawing
|
||||||
|
open System.Drawing.Imaging
|
||||||
|
open System.Collections.Concurrent
|
||||||
|
open System.Runtime.InteropServices
|
||||||
|
open FSharp.Collections.ParallelSeq
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Listing 4.1 Complex number object
|
||||||
|
type Complex(real : float, imaginary : float) =
|
||||||
|
member this.Real = real
|
||||||
|
member this.Imaginary = imaginary
|
||||||
|
|
||||||
|
member this.Magnitude =
|
||||||
|
sqrt(this.Real * this.Real + this.Imaginary * this.Imaginary)
|
||||||
|
|
||||||
|
static member (+) (c1 : Complex, c2 : Complex) =
|
||||||
|
new Complex(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary)
|
||||||
|
static member (*) (c1 : Complex, c2 : Complex) =
|
||||||
|
new Complex(c1.Real * c2.Real - c1.Imaginary * c2.Imaginary,
|
||||||
|
c1.Real * c2.Imaginary + c1.Imaginary * c2.Real)
|
||||||
|
|
||||||
|
let parallelMandelbrot() =
|
||||||
|
let rows, cols = 2000, 2000
|
||||||
|
let center = Complex(-0.75, 0.0)
|
||||||
|
let width, height = 2.5, 2.5
|
||||||
|
|
||||||
|
let colToX col = center.Real - width / 2.0 +
|
||||||
|
float(col) * width / float(cols)
|
||||||
|
let rowToY row = center.Imaginary - height / 2.0 +
|
||||||
|
float(row) * height / float(rows)
|
||||||
|
|
||||||
|
let isMandelbrot c iterations =
|
||||||
|
let rec isMandelbrot (z:Complex) (rep:int) =
|
||||||
|
if rep < iterations && z.Magnitude < 2.0 then
|
||||||
|
isMandelbrot (z * z + c) (rep + 1)
|
||||||
|
else rep = iterations
|
||||||
|
isMandelbrot c 0
|
||||||
|
|
||||||
|
let bitmap = new Bitmap(rows, cols, PixelFormat.Format24bppRgb)
|
||||||
|
let width, height = bitmap.Width, bitmap.Height
|
||||||
|
let bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
|
||||||
|
|
||||||
|
let byteCount = bitmapData.Stride * height
|
||||||
|
let pixels : byte[] = Array.zeroCreate<byte> byteCount
|
||||||
|
let ptrFirstPixel = bitmapData.Scan0
|
||||||
|
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length)
|
||||||
|
|
||||||
|
Partitioner.Create(0, cols - 1).AsParallel()
|
||||||
|
|> PSeq.withDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
|> PSeq.withMergeOptions(ParallelMergeOptions.FullyBuffered)
|
||||||
|
|> PSeq.iter(fun (s,e) ->
|
||||||
|
for col = s to e - 1 do
|
||||||
|
for row = 0 to rows - 1 do
|
||||||
|
let x,y = colToX row, rowToY col
|
||||||
|
let c = Complex(x, y)
|
||||||
|
let color = if isMandelbrot c 100 then Color.Black else Color.White
|
||||||
|
let offset = (col * bitmapData.Stride) + (3 * row)
|
||||||
|
pixels.[offset + 0] <- color.B; // Red component
|
||||||
|
pixels.[offset + 1] <- color.G; // Green component
|
||||||
|
pixels.[offset + 2] <- color.R; // Blue component
|
||||||
|
)
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length)
|
||||||
|
bitmap.UnlockBits(bitmapData)
|
||||||
|
bitmap.Clone() :?> Bitmap
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
[<Struct>]
|
||||||
|
type ComplexStruct(real : float, imaginary : float) =
|
||||||
|
member this.Real = real
|
||||||
|
member this.Imaginary = imaginary
|
||||||
|
|
||||||
|
member this.Magnitude =
|
||||||
|
sqrt(this.Real * this.Real + this.Imaginary * this.Imaginary)
|
||||||
|
|
||||||
|
static member (+) (c1 : ComplexStruct, c2 : ComplexStruct) =
|
||||||
|
new ComplexStruct(c1.Real + c2.Real, c1.Imaginary + c2.Imaginary)
|
||||||
|
static member (*) (c1 : ComplexStruct, c2 : ComplexStruct) =
|
||||||
|
new ComplexStruct(c1.Real * c2.Real - c1.Imaginary * c2.Imaginary,
|
||||||
|
c1.Real * c2.Imaginary + c1.Imaginary * c2.Real)
|
||||||
|
|
||||||
|
let parallelMandelbrotStruct() =
|
||||||
|
let rows, cols = 2000, 2000
|
||||||
|
let center = ComplexStruct(-0.75, 0.0)
|
||||||
|
let width, height = 2.5, 2.5
|
||||||
|
|
||||||
|
let colToX col = center.Real - width / 2.0 +
|
||||||
|
float(col) * width / float(cols)
|
||||||
|
let rowToY row = center.Imaginary - height / 2.0 +
|
||||||
|
float(row) * height / float(rows)
|
||||||
|
|
||||||
|
let isMandelbrot c iterations =
|
||||||
|
let rec isMandelbrot (z:ComplexStruct) (rep:int) =
|
||||||
|
if rep < iterations && z.Magnitude < 2.0 then
|
||||||
|
isMandelbrot (z * z + c) (rep + 1)
|
||||||
|
else rep = iterations
|
||||||
|
isMandelbrot c 0
|
||||||
|
|
||||||
|
let bitmap = new Bitmap(rows, cols, PixelFormat.Format24bppRgb)
|
||||||
|
let width, height = bitmap.Width, bitmap.Height
|
||||||
|
let bitmapData = bitmap.LockBits(new Rectangle(0, 0, width, height),
|
||||||
|
ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb)
|
||||||
|
|
||||||
|
let byteCount = bitmapData.Stride * height
|
||||||
|
let pixels : byte[] = Array.zeroCreate<byte> byteCount
|
||||||
|
let ptrFirstPixel = bitmapData.Scan0
|
||||||
|
|
||||||
|
Marshal.Copy(ptrFirstPixel, pixels, 0, pixels.Length)
|
||||||
|
|
||||||
|
Partitioner.Create(0, cols - 1).AsParallel()
|
||||||
|
|> PSeq.withDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
|> PSeq.withMergeOptions(ParallelMergeOptions.FullyBuffered)
|
||||||
|
|> PSeq.iter(fun (s,e) ->
|
||||||
|
for col = s to e - 1 do
|
||||||
|
for row = 0 to rows - 1 do
|
||||||
|
let x,y = colToX row, rowToY col
|
||||||
|
let c = ComplexStruct(x, y)
|
||||||
|
let color = if isMandelbrot c 100 then Color.Blue else Color.White
|
||||||
|
let offset = (col * bitmapData.Stride) + (3 * row)
|
||||||
|
pixels.[offset + 0] <- color.B; // Red component
|
||||||
|
pixels.[offset + 1] <- color.G; // Green component
|
||||||
|
pixels.[offset + 2] <- color.R; // Blue component
|
||||||
|
)
|
||||||
|
|
||||||
|
Marshal.Copy(pixels, 0, ptrFirstPixel, pixels.Length)
|
||||||
|
bitmap.UnlockBits(bitmapData)
|
||||||
|
bitmap.Clone() :?> Bitmap
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
module PrimeNumbers
|
||||||
|
|
||||||
|
open System
|
||||||
|
open System.Linq
|
||||||
|
open System.Collections.Concurrent
|
||||||
|
open FSharp.Collections.ParallelSeq
|
||||||
|
|
||||||
|
let len = 1000000//0
|
||||||
|
let isPrime n =
|
||||||
|
if n < 2 then false
|
||||||
|
elif n = 2 then true
|
||||||
|
else
|
||||||
|
let boundary = int(Math.Floor(Math.Sqrt(float(n))))
|
||||||
|
[2..boundary]
|
||||||
|
|> Seq.exists (fun i-> (n%i)=0)
|
||||||
|
|> not
|
||||||
|
|
||||||
|
let sequentialSum () =
|
||||||
|
Seq.init len id
|
||||||
|
|> Seq.filter (isPrime)
|
||||||
|
|> Seq.sumBy (fun x-> int64(x))
|
||||||
|
|
||||||
|
let parallelSum () =
|
||||||
|
Seq.init len id
|
||||||
|
|> PSeq.withDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
|> PSeq.withMergeOptions(ParallelMergeOptions.FullyBuffered)
|
||||||
|
|> PSeq.filter (isPrime)
|
||||||
|
|> Seq.sumBy (fun x-> int64(x))
|
||||||
|
|
||||||
|
let parallelLinqSum () =
|
||||||
|
(Seq.init len id).AsParallel().Where(isPrime).Sum(fun x -> int64(x))
|
|
@ -0,0 +1,53 @@
|
||||||
|
open System.Windows.Forms
|
||||||
|
open System.Drawing
|
||||||
|
open System
|
||||||
|
|
||||||
|
let ``run Mandelbrot Performance Comparison``() =
|
||||||
|
Demo.printSeparator()
|
||||||
|
printfn "Mandelbrot Performance Comparison"
|
||||||
|
let run func = [func >> ignore]
|
||||||
|
[
|
||||||
|
"F# Parallel" , run Mandelbrot.parallelMandelbrot
|
||||||
|
"F# Parallel Struct" , run Mandelbrot.parallelMandelbrotStruct
|
||||||
|
]
|
||||||
|
|> PerfVis.toChart "F# Mandelbrot"
|
||||||
|
|> Application.Run
|
||||||
|
|
||||||
|
let ``run Draw Mandelbrot``() =
|
||||||
|
Demo.printSeparator()
|
||||||
|
printfn "Draw Mandelbrot"
|
||||||
|
let image = Mandelbrot.parallelMandelbrotStruct()
|
||||||
|
let form = new Form(Visible = true, Text = "Mandelbrot",
|
||||||
|
TopMost = true, Size = Size(800,800))
|
||||||
|
new PictureBox(Dock = DockStyle.Fill, Image = image,
|
||||||
|
SizeMode = PictureBoxSizeMode.StretchImage)
|
||||||
|
|> form.Controls.Add
|
||||||
|
Application.Run(form)
|
||||||
|
|
||||||
|
let ``run Prime Sum [0..10^7]``() =
|
||||||
|
Demo.printSeparator()
|
||||||
|
printfn "Prime Sum [0..10^7]"
|
||||||
|
let runSum func =
|
||||||
|
[fun() ->
|
||||||
|
let res = func()
|
||||||
|
printfn "Sum = %d" res
|
||||||
|
]
|
||||||
|
[
|
||||||
|
"F# Sequential" , runSum PrimeNumbers.sequentialSum
|
||||||
|
"F# Parallel" , runSum PrimeNumbers.parallelSum
|
||||||
|
"F# Parallel LINQ" , runSum PrimeNumbers.parallelLinqSum
|
||||||
|
]
|
||||||
|
|> PerfVis.toChart "F# Prime Sum"
|
||||||
|
|> Application.Run
|
||||||
|
|
||||||
|
[<EntryPoint>]
|
||||||
|
let main argv =
|
||||||
|
|
||||||
|
``run Mandelbrot Performance Comparison``()
|
||||||
|
|
||||||
|
//``run Draw Mandelbrot``()
|
||||||
|
//``run Prime Sum [0..10^7]``()
|
||||||
|
|
||||||
|
Console.ReadLine() |> ignore
|
||||||
|
|
||||||
|
0
|
|
@ -0,0 +1,5 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<packages>
|
||||||
|
<package id="FSharp.Collections.ParallelSeq" version="1.0.2" targetFramework="net461" />
|
||||||
|
<package id="FSharp.Core" version="4.3.4" targetFramework="net47" />
|
||||||
|
</packages>
|
|
@ -0,0 +1,192 @@
|
||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<Project ToolsVersion="14.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||||
|
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
|
||||||
|
<PropertyGroup>
|
||||||
|
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
|
||||||
|
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
|
||||||
|
<ProjectGuid>{D1CD7806-99BF-463D-807D-AF5DE50EA49C}</ProjectGuid>
|
||||||
|
<OutputType>Exe</OutputType>
|
||||||
|
<AppDesignerFolder>Properties</AppDesignerFolder>
|
||||||
|
<RootNamespace>DataParallelism.Part2</RootNamespace>
|
||||||
|
<AssemblyName>DataParallelism.Part2.cs</AssemblyName>
|
||||||
|
<TargetFrameworkVersion>v4.7</TargetFrameworkVersion>
|
||||||
|
<FileAlignment>512</FileAlignment>
|
||||||
|
<TargetFrameworkProfile />
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
|
||||||
|
<DebugSymbols>true</DebugSymbols>
|
||||||
|
<DebugType>full</DebugType>
|
||||||
|
<Optimize>false</Optimize>
|
||||||
|
<OutputPath>bin\Debug\</OutputPath>
|
||||||
|
<DefineConstants>DEBUG;TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
|
||||||
|
<DebugType>pdbonly</DebugType>
|
||||||
|
<Optimize>true</Optimize>
|
||||||
|
<OutputPath>bin\Release\</OutputPath>
|
||||||
|
<DefineConstants>TRACE</DefineConstants>
|
||||||
|
<ErrorReport>prompt</ErrorReport>
|
||||||
|
<WarningLevel>4</WarningLevel>
|
||||||
|
</PropertyGroup>
|
||||||
|
<PropertyGroup>
|
||||||
|
<StartupObject>DataParallelism.Part2.CSharp.Program</StartupObject>
|
||||||
|
</PropertyGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Reference Include="FSharp.Core, Version=4.4.3.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
|
||||||
|
<HintPath>..\..\packages\FSharp.Core.4.3.4\lib\net45\FSharp.Core.dll</HintPath>
|
||||||
|
<Private>True</Private>
|
||||||
|
</Reference>
|
||||||
|
<Reference Include="System" />
|
||||||
|
<Reference Include="System.Core" />
|
||||||
|
<Reference Include="System.Drawing" />
|
||||||
|
<Reference Include="System.Windows.Forms" />
|
||||||
|
<Reference Include="System.Xml.Linq" />
|
||||||
|
<Reference Include="System.Data.DataSetExtensions" />
|
||||||
|
<Reference Include="Microsoft.CSharp" />
|
||||||
|
<Reference Include="System.Data" />
|
||||||
|
<Reference Include="System.Net.Http" />
|
||||||
|
<Reference Include="System.Xml" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Compile Include="KMeans.cs" />
|
||||||
|
<Compile Include="MapReduce.PLINQ.cs" />
|
||||||
|
<Compile Include="MapReduce.PLINQPartitioner.cs" />
|
||||||
|
<Compile Include="ParalellReduce.cs" />
|
||||||
|
<Compile Include="Program.cs" />
|
||||||
|
<Compile Include="WordsCounter.cs" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<ProjectReference Include="..\..\Common\Functional.cs\Functional.cs.csproj">
|
||||||
|
<Project>{24d84c19-b173-4635-91a6-42328bc694ce}</Project>
|
||||||
|
<Name>Functional.cs</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
<ProjectReference Include="..\..\Common\Utilities\Utilities.fsproj">
|
||||||
|
<Project>{2c133fbd-c138-43bb-9066-a9fecb1abe86}</Project>
|
||||||
|
<Name>Utilities</Name>
|
||||||
|
</ProjectReference>
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<None Include="app.config" />
|
||||||
|
<None Include="packages.config" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Folder Include="Properties\" />
|
||||||
|
</ItemGroup>
|
||||||
|
<ItemGroup>
|
||||||
|
<Content Include="Shakespeare\allswellthatendswell.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\amsnd.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\antandcleo.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\asyoulikeit.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\comedyoferrors.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\cymbeline.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\hamlet.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryiv1.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryiv2.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryv.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryvi1.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryvi2.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryvi3.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\henryviii.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\juliuscaesar.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\kingjohn.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\kinglear.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\loveslobourslost.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\maan.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\macbeth.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\measureformeasure.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\merchantofvenice.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\othello.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\richardii.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\richardiii.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\romeoandjuliet.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\tamingoftheshrew.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\tempest.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\themwofw.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\thetgofv.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\timon.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\titus.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\troilusandcressida.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\twelfthnight.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="Shakespeare\winterstale.txt">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
</ItemGroup>
|
||||||
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
|
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
|
||||||
|
Other similar extension points exist, see Microsoft.Common.targets.
|
||||||
|
<Target Name="BeforeBuild">
|
||||||
|
</Target>
|
||||||
|
<Target Name="AfterBuild">
|
||||||
|
</Target>
|
||||||
|
-->
|
||||||
|
</Project>
|
|
@ -0,0 +1,170 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.Part2.CSharp
|
||||||
|
{
|
||||||
|
public class KMeans
|
||||||
|
{
|
||||||
|
public KMeans(double[][] data)
|
||||||
|
{
|
||||||
|
this.data = data;
|
||||||
|
this.N = data[0].Length;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected int N;
|
||||||
|
protected double[][] data;
|
||||||
|
|
||||||
|
private double Dist(double[] u, double[] v)
|
||||||
|
{
|
||||||
|
double results = 0.0;
|
||||||
|
for (var i = 0; i < u.Length; i++)
|
||||||
|
results += Math.Pow(u[i] - v[i], 2.0);
|
||||||
|
return results;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Listing 5.8 Function to find the closest centroid(used to update the clusters)
|
||||||
|
protected double[] GetNearestCentroid(double[][] centroids, double[] center)
|
||||||
|
{
|
||||||
|
return centroids.Aggregate((centroid1, centroid2) => //#A
|
||||||
|
Dist(center, centroid2) < Dist(center, centroid1)
|
||||||
|
? centroid2
|
||||||
|
: centroid1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Listing 5.9 Update the location of the centroids according to the center of the cluster
|
||||||
|
protected virtual double[][] UpdateCentroids(double[][] centroids)
|
||||||
|
{
|
||||||
|
var partitioner = Partitioner.Create(data, true); //#A
|
||||||
|
var result = partitioner.AsParallel() //#B
|
||||||
|
.WithExecutionMode(ParallelExecutionMode.ForceParallelism) //#C
|
||||||
|
.GroupBy(u => GetNearestCentroid(centroids, u))
|
||||||
|
.Select(points =>
|
||||||
|
points
|
||||||
|
.Aggregate(new double[N], //#D
|
||||||
|
(acc, item) => acc.Zip(item, (a, b) => a + b).ToArray()) //#E
|
||||||
|
.Select(items => items / points.Count())
|
||||||
|
.ToArray())
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Array.Sort(result, (a, b) => {
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return a[i].CompareTo(b[i]);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
//Listing 5.10 UpdateCentroids function implemented without Aggregate
|
||||||
|
double[][] UpdateCentroidsWithMutableState(double[][] centroids)
|
||||||
|
{
|
||||||
|
var result = data.AsParallel()
|
||||||
|
.GroupBy(u => GetNearestCentroid(centroids, u))
|
||||||
|
.Select(points => {
|
||||||
|
var res = new double[N];
|
||||||
|
foreach (var x in points) //#A
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] += x[i]; //#B
|
||||||
|
var count = points.Count();
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] /= count; //#B
|
||||||
|
return res;
|
||||||
|
});
|
||||||
|
return result.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
public double[][] Run(double[][] initialCentroids)
|
||||||
|
{
|
||||||
|
var centroids = initialCentroids;
|
||||||
|
for (int i = 0; i <= 1000; i++)
|
||||||
|
{
|
||||||
|
var newCentroids = UpdateCentroids(centroids);
|
||||||
|
var error = double.MaxValue;
|
||||||
|
if (centroids.Length == newCentroids.Length)
|
||||||
|
{
|
||||||
|
error = 0;
|
||||||
|
for (var j = 0; j < centroids.Length; j++)
|
||||||
|
error += Dist(centroids[j], newCentroids[j]);
|
||||||
|
}
|
||||||
|
if (error < 1e-9)
|
||||||
|
{
|
||||||
|
Console.WriteLine($"Iterations {i}");
|
||||||
|
return newCentroids;
|
||||||
|
}
|
||||||
|
centroids = newCentroids;
|
||||||
|
}
|
||||||
|
Console.WriteLine($"Iterations 1000");
|
||||||
|
return centroids;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KMeansLinq : KMeans
|
||||||
|
{
|
||||||
|
public KMeansLinq(double[][] data) : base(data)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override double[][] UpdateCentroids(double[][] centroids)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
data
|
||||||
|
.GroupBy(u => GetNearestCentroid(centroids, u))
|
||||||
|
.Select(elements => {
|
||||||
|
var res = new double[N];
|
||||||
|
foreach (var x in elements)
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] += x[i];
|
||||||
|
var M = elements.Count();
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] /= M;
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Array.Sort(result, (a, b) => {
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return a[i].CompareTo(b[i]);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public class KMeansPLinq : KMeans
|
||||||
|
{
|
||||||
|
public KMeansPLinq(double[][] data) : base(data)
|
||||||
|
{ }
|
||||||
|
|
||||||
|
protected override double[][] UpdateCentroids(double[][] centroids)
|
||||||
|
{
|
||||||
|
var result =
|
||||||
|
data.AsParallel()
|
||||||
|
.GroupBy(u => GetNearestCentroid(centroids, u))
|
||||||
|
.Select(elements => {
|
||||||
|
var res = new double[N];
|
||||||
|
foreach (var x in elements)
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] += x[i];
|
||||||
|
var M = elements.Count();
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
res[i] /= M;
|
||||||
|
return res;
|
||||||
|
})
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
Array.Sort(result, (a, b) => {
|
||||||
|
for (var i = 0; i < N; i++)
|
||||||
|
if (a[i] != b[i])
|
||||||
|
return a[i].CompareTo(b[i]);
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
|
@ -0,0 +1,35 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace DataParallelism.Part2.CSharp
|
||||||
|
{
|
||||||
|
using static Functional.Functional;
|
||||||
|
|
||||||
|
public static class MapReducePLINQ
|
||||||
|
{
|
||||||
|
public static TResult[] MapReduce<TSource, TMapped, TKey, TResult>(
|
||||||
|
this IList<TSource> source,
|
||||||
|
Func<TSource, IEnumerable<TMapped>> map,
|
||||||
|
Func<TMapped, TKey> keySelector,
|
||||||
|
Func<IGrouping<TKey, TMapped>, TResult> reduce,
|
||||||
|
int M, int R)
|
||||||
|
{
|
||||||
|
return source.AsParallel()
|
||||||
|
.WithDegreeOfParallelism(M)
|
||||||
|
.SelectMany(map)
|
||||||
|
.GroupBy(keySelector)
|
||||||
|
.ToList().AsParallel()
|
||||||
|
.WithDegreeOfParallelism(R)
|
||||||
|
.Select(reduce)
|
||||||
|
.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public static IEnumerable<IGrouping<TKey, TMapped>> Map<TSource, TKey, TMapped>(this IList<TSource> source, Func<TSource, IEnumerable<TMapped>> map, Func<TMapped, TKey> keySelector) =>
|
||||||
|
source.AsParallel()
|
||||||
|
.WithDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
.SelectMany(map)
|
||||||
|
.GroupBy(keySelector)
|
||||||
|
.ToList();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Concurrent;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
|
||||||
|
namespace DataParallelism.Part2.CSharp
|
||||||
|
{
|
||||||
|
public static class MapReducePLINQPartitioner
|
||||||
|
{
|
||||||
|
public static TResult[] MapReduce<TSource, TMapped, TKey, TResult>(
|
||||||
|
this IList<TSource> source,
|
||||||
|
Func<TSource, IEnumerable<TMapped>> map,
|
||||||
|
Func<TMapped, TKey> keySelector,
|
||||||
|
Func<IGrouping<TKey, TMapped>, TResult> reduce,
|
||||||
|
int M, int R)
|
||||||
|
{
|
||||||
|
var partitioner = Partitioner.Create(source, true);
|
||||||
|
|
||||||
|
var mapResults =
|
||||||
|
partitioner.AsParallel()
|
||||||
|
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
|
||||||
|
.WithDegreeOfParallelism(M)
|
||||||
|
.SelectMany(map)
|
||||||
|
.GroupBy(keySelector)
|
||||||
|
.ToList().AsParallel()
|
||||||
|
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
|
||||||
|
.WithDegreeOfParallelism(R)
|
||||||
|
.Select(reduce)
|
||||||
|
.ToArray();
|
||||||
|
|
||||||
|
return mapResults;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace DataParallelism.Part2.CSharp
|
||||||
|
{
|
||||||
|
using static Functional.Functional;
|
||||||
|
|
||||||
|
|
||||||
|
public static class ParalellMapReduce
|
||||||
|
{
|
||||||
|
// Listing 5.11 A parallel Reduce function implementation using Aggregate
|
||||||
|
public static TValue Reduce<TValue>(this ParallelQuery<TValue> source, Func<TValue, TValue, TValue> reduce) =>
|
||||||
|
ParallelEnumerable.Aggregate(source, //#A
|
||||||
|
(item1, item2) => reduce(item1, item2)); //#B
|
||||||
|
|
||||||
|
|
||||||
|
public static TValue Reduce<TValue>(this IEnumerable<TValue> source, TValue seed,
|
||||||
|
Func<TValue, TValue, TValue> reduce) =>
|
||||||
|
source.AsParallel()
|
||||||
|
.Aggregate(
|
||||||
|
seed: seed,
|
||||||
|
updateAccumulatorFunc: (local, value) => reduce(local, value),
|
||||||
|
combineAccumulatorsFunc: (overall, local) => reduce(overall, local),
|
||||||
|
resultSelector: overall => overall);
|
||||||
|
|
||||||
|
public static Func<Func<TSource, TSource, TSource>, TSource> Reduce<TSource>(this IEnumerable<TSource> source)
|
||||||
|
=> func => source.AsParallel().Aggregate((item1, item2) => func(item1, item2));
|
||||||
|
|
||||||
|
public static IEnumerable<IGrouping<TKey, TMapped>> Map<TSource, TKey, TMapped>(this IList<TSource> source, Func<TSource, IEnumerable<TMapped>> map, Func<TMapped, TKey> keySelector) =>
|
||||||
|
source.AsParallel()
|
||||||
|
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
|
||||||
|
.WithDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
.SelectMany(map)
|
||||||
|
.GroupBy(keySelector)
|
||||||
|
.ToList();
|
||||||
|
|
||||||
|
public static TResult[] Reduce<TSource, TKey, TMapped, TResult>(this IEnumerable<IGrouping<TKey, TMapped>> source, Func<IGrouping<TKey, TMapped>, TResult> reduce) =>
|
||||||
|
source.AsParallel()
|
||||||
|
.WithExecutionMode(ParallelExecutionMode.ForceParallelism)
|
||||||
|
.WithDegreeOfParallelism(Environment.ProcessorCount)
|
||||||
|
.Select(reduce).ToArray();
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DataParallelism.Part2.CSharp
|
||||||
|
{
|
||||||
|
public static class Program
|
||||||
|
{
|
||||||
|
public static void Main(string[] args)
|
||||||
|
{
|
||||||
|
Console.WriteLine("WordCount");
|
||||||
|
WordsCounterDemo.Demo();
|
||||||
|
|
||||||
|
Demo.PrintSeparator();
|
||||||
|
Console.WriteLine("Listing 5.11 A parallel Reduce function implementation using Aggregate");
|
||||||
|
|
||||||
|
int[] source = Enumerable.Range(0, 100000).ToArray();
|
||||||
|
int result = source.AsParallel()
|
||||||
|
.Reduce((value1, value2) => value1 + value2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
File diff suppressed because it is too large
Load diff
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue