├── .gitignore ├── .nuget └── packages.config ├── .travis.yml ├── FsControl.BaseLib ├── BitConverter.cs ├── FsControl.BaseLib.csproj └── Properties │ └── AssemblyInfo.cs ├── FsControl.Core ├── AssemblyInfo.fs ├── Collection.fs ├── Converter.fs ├── Foldable.fs ├── FsControl.Core.fsproj ├── FsControl.Core.nuspec ├── Functor.fs ├── Indexable.fs ├── Internals.fs ├── MonadTrans.fs ├── Monoid.fs ├── Numeric.fs ├── Operators.fs ├── Samples │ ├── Collections.fsx │ ├── Converter.fsx │ ├── Functions.fsx │ ├── Haskell.fsx │ └── Numerics.fsx ├── Traversable.fs └── Tuple.fs ├── FsControl.Test ├── App.config ├── FsControl.Test.fsproj ├── MSTest.runsettings ├── UnitTest.fs └── packages.config ├── FsControl.sln ├── LICENSE.md ├── README.md ├── build.fsx └── makefile.fsx /.gitignore: -------------------------------------------------------------------------------- 1 | *.suo 2 | *.bak 3 | *.user 4 | *.cache 5 | */bin 6 | */obj 7 | _ReSharper.* -------------------------------------------------------------------------------- /.nuget/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | 3 | env: 4 | global: 5 | - EnableNuGetPackageRestore=true 6 | matrix: 7 | - MONO_VERSION="4.2.1" 8 | 9 | before_install: 10 | - wget "http://download.mono-project.com/archive/${MONO_VERSION}/macos-10-x86/MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" 11 | - sudo installer -pkg "MonoFramework-MDK-${MONO_VERSION}.macos10.xamarin.x86.pkg" -target / 12 | - mozroots --import --sync 13 | 14 | script: 15 | - ./build.fsx -------------------------------------------------------------------------------- /FsControl.BaseLib/BitConverter.cs: -------------------------------------------------------------------------------- 1 | // ==++== 2 | // 3 | // Copyright (c) Microsoft Corporation. All rights reserved. 4 | // 5 | // ==--== 6 | /*============================================================ 7 | ** 8 | ** Class: BitConverter 9 | ** 10 | ** 11 | ** Purpose: Allows developers to view the base data types as 12 | ** an arbitrary array of bits. 13 | ** 14 | ** 15 | ===========================================================*/ 16 | namespace FsControl.BaseLib 17 | { 18 | 19 | using System; 20 | 21 | // The BitConverter class contains methods for 22 | // converting an array of bytes to one of the base data 23 | // types, as well as for converting a base data type to an 24 | // array of bytes. 25 | // 26 | // Only statics, does not need to be marked with the serializable attribute 27 | public static class BitConverter 28 | { 29 | 30 | // This field indicates the "endianess" of the architecture. 31 | // The value is set to true if the architecture is 32 | // little endian; false if it is big endian. 33 | //#if BIGENDIAN 34 | // public static readonly bool IsLittleEndian /* = false */; 35 | //#else 36 | // public static readonly bool IsLittleEndian = true; 37 | //#endif 38 | 39 | // Converts a byte into an array of bytes with length one. 40 | public static byte[] GetBytes(bool value) 41 | { 42 | byte[] r = new byte[1]; 43 | r[0] = (value ? (byte) 1 : (byte) 0); 44 | return r; 45 | } 46 | 47 | // Converts a char into an array of bytes with length two. 48 | public static byte[] GetBytes(char value, bool isLittleEndian) 49 | { 50 | return GetBytes((short)value, isLittleEndian); 51 | } 52 | 53 | // Converts a short into an array of bytes with length 54 | // two. 55 | public unsafe static byte[] GetBytes(short value, bool isLittleEndian) 56 | { 57 | if (!isLittleEndian) return new [] {(byte)(value >> 8), (byte)value}; 58 | byte[] bytes = new byte[2]; 59 | fixed (byte* b = bytes) 60 | *((short*)b) = value; 61 | return bytes; 62 | } 63 | 64 | // Converts an int into an array of bytes with length 65 | // four. 66 | public unsafe static byte[] GetBytes(int value, bool isLittleEndian) 67 | { 68 | if (!isLittleEndian) return new [] {(byte)(value >> 24), (byte)(value >> 16), (byte)(value >> 8), (byte)value}; 69 | byte[] bytes = new byte[4]; 70 | fixed (byte* b = bytes) 71 | *((int*)b) = value; 72 | return bytes; 73 | } 74 | 75 | // Converts a long into an array of bytes with length 76 | // eight. 77 | public unsafe static byte[] GetBytes(long value, bool isLittleEndian) 78 | { 79 | if (!isLittleEndian) return new [] {(byte)(value >> 56), (byte)(value >> 48), (byte)(value >> 40), (byte)(value >> 32), (byte)(value >> 24), (byte)(value >> 16), (byte)(value >> 8), (byte)value}; 80 | byte[] bytes = new byte[8]; 81 | fixed (byte* b = bytes) 82 | *((long*)b) = value; 83 | return bytes; 84 | } 85 | 86 | // Converts an ushort into an array of bytes with 87 | // length two. 88 | public static byte[] GetBytes(ushort value, bool isLittleEndian) 89 | { 90 | return GetBytes((short)value, isLittleEndian); 91 | } 92 | 93 | // Converts an uint into an array of bytes with 94 | // length four. 95 | public static byte[] GetBytes(uint value, bool isLittleEndian) 96 | { 97 | return GetBytes((int)value, isLittleEndian); 98 | } 99 | 100 | // Converts an unsigned long into an array of bytes with 101 | // length eight. 102 | public static byte[] GetBytes(ulong value, bool isLittleEndian) 103 | { 104 | return GetBytes((long)value, isLittleEndian); 105 | } 106 | 107 | // Converts a float into an array of bytes with length 108 | // four. 109 | public unsafe static byte[] GetBytes(float value, bool isLittleEndian) 110 | { 111 | return GetBytes(*(int*)&value, isLittleEndian); 112 | } 113 | 114 | // Converts a double into an array of bytes with length 115 | // eight. 116 | public unsafe static byte[] GetBytes(double value, bool isLittleEndian) 117 | { 118 | return GetBytes(*(long*)&value, isLittleEndian); 119 | } 120 | 121 | // Converts an array of bytes into a char. 122 | public static char ToChar(byte[] value, int startIndex, bool isLittleEndian) 123 | { 124 | return (char)ToInt16(value, startIndex, isLittleEndian); 125 | } 126 | 127 | // Converts an array of bytes into a short. 128 | public static unsafe short ToInt16(byte[] value, int startIndex, bool isLittleEndian) 129 | { 130 | if (value == null) 131 | throw new ArgumentNullException(nameof(value)); 132 | 133 | if ((uint)startIndex >= value.Length) 134 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_Index"); 135 | 136 | if (startIndex > value.Length - 2) 137 | throw new ArgumentException("Arg_ArrayPlusOffTooSmall"); 138 | 139 | fixed (byte* pbyte = &value[startIndex]) 140 | { 141 | if (isLittleEndian) 142 | { 143 | if (startIndex % 2 == 0) // data is aligned 144 | return *((short*)pbyte); 145 | 146 | return (short)((*pbyte) | (*(pbyte + 1) << 8)); 147 | } 148 | return (short)((*pbyte << 8) | (*(pbyte + 1))); 149 | } 150 | } 151 | 152 | // Converts an array of bytes into an int. 153 | public static unsafe int ToInt32(byte[] value, int startIndex, bool isLittleEndian) 154 | { 155 | if (value == null) 156 | throw new ArgumentNullException(nameof(value)); 157 | 158 | if ((uint)startIndex >= value.Length) 159 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_Index"); 160 | 161 | if (startIndex > value.Length - 4) 162 | throw new ArgumentException("Arg_ArrayPlusOffTooSmall"); 163 | 164 | fixed (byte* pbyte = &value[startIndex]) 165 | { 166 | if (isLittleEndian) 167 | { 168 | if (startIndex % 4 == 0) // data is aligned 169 | return *((int*)pbyte); 170 | 171 | return (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24); 172 | } 173 | return (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); 174 | } 175 | } 176 | 177 | // Converts an array of bytes into a long. 178 | public static unsafe long ToInt64(byte[] value, int startIndex, bool isLittleEndian) 179 | { 180 | if (value == null) 181 | throw new ArgumentNullException(nameof(value)); 182 | 183 | if ((uint)startIndex >= value.Length) 184 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_Index"); 185 | 186 | if (startIndex > value.Length - 8) 187 | throw new ArgumentException("Arg_ArrayPlusOffTooSmall"); 188 | 189 | fixed (byte* pbyte = &value[startIndex]) 190 | { 191 | if (isLittleEndian) 192 | { 193 | if (startIndex % 8 == 0) // data is aligned 194 | return *((long*)pbyte); 195 | 196 | int i1 = (*pbyte) | (*(pbyte + 1) << 8) | (*(pbyte + 2) << 16) | (*(pbyte + 3) << 24); 197 | int i2 = (*(pbyte + 4)) | (*(pbyte + 5) << 8) | (*(pbyte + 6) << 16) | (*(pbyte + 7) << 24); 198 | return (uint)i1 | ((long)i2 << 32); 199 | } 200 | else 201 | { 202 | int i1 = (*pbyte << 24) | (*(pbyte + 1) << 16) | (*(pbyte + 2) << 8) | (*(pbyte + 3)); 203 | int i2 = (*(pbyte + 4) << 24) | (*(pbyte + 5) << 16) | (*(pbyte + 6) << 8) | (*(pbyte + 7)); 204 | return (uint)i2 | ((long)i1 << 32); 205 | } 206 | } 207 | } 208 | 209 | 210 | // Converts an array of bytes into an ushort. 211 | // 212 | public static ushort ToUInt16(byte[] value, int startIndex, bool isLittleEndian) 213 | { 214 | return (ushort)ToInt16(value, startIndex, isLittleEndian); 215 | } 216 | 217 | // Converts an array of bytes into an uint. 218 | // 219 | public static uint ToUInt32(byte[] value, int startIndex, bool isLittleEndian) 220 | { 221 | return (uint)ToInt32(value, startIndex, isLittleEndian); 222 | } 223 | 224 | // Converts an array of bytes into an unsigned long. 225 | // 226 | public static ulong ToUInt64(byte[] value, int startIndex, bool isLittleEndian) 227 | { 228 | return (ulong)ToInt64(value, startIndex, isLittleEndian); 229 | } 230 | 231 | // Converts an array of bytes into a float. 232 | unsafe public static float ToSingle(byte[] value, int startIndex, bool isLittleEndian) 233 | { 234 | int val = ToInt32(value, startIndex, isLittleEndian); 235 | return *(float*)&val; 236 | } 237 | 238 | // Converts an array of bytes into a double. 239 | unsafe public static double ToDouble(byte[] value, int startIndex, bool isLittleEndian) 240 | { 241 | long val = ToInt64(value, startIndex, isLittleEndian); 242 | return *(double*)&val; 243 | } 244 | 245 | private static char GetHexValue(int i) 246 | { 247 | System.Diagnostics.Debug.Assert(i >= 0 && i < 16, "i is out of range."); 248 | if (i < 10) 249 | { 250 | return (char)(i + '0'); 251 | } 252 | 253 | return (char)(i - 10 + 'A'); 254 | } 255 | 256 | // Converts an array of bytes into a String. 257 | public static String ToString(byte[] value, int startIndex, int length) 258 | { 259 | 260 | if (value == null) 261 | { 262 | throw new ArgumentNullException(nameof(value)); 263 | } 264 | 265 | int arrayLen = value.Length; 266 | if (startIndex < 0 || (startIndex >= arrayLen && startIndex > 0)) 267 | { 268 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_StartIndex"); 269 | } 270 | 271 | int realLength = length; 272 | if (realLength < 0) 273 | { 274 | throw new ArgumentOutOfRangeException(nameof(length), "ArgumentOutOfRange_GenericPositive"); 275 | } 276 | 277 | if (startIndex > arrayLen - realLength) 278 | { 279 | throw new ArgumentException("Arg_ArrayPlusOffTooSmall"); 280 | } 281 | 282 | if (realLength == 0) 283 | { 284 | return string.Empty; 285 | } 286 | 287 | char[] chArray = new char[realLength * 3]; 288 | int i = 0; 289 | int index = startIndex; 290 | for (i = 0; i < realLength * 3; i += 3) 291 | { 292 | byte b = value[index++]; 293 | chArray[i] = GetHexValue(b / 16); 294 | chArray[i + 1] = GetHexValue(b % 16); 295 | chArray[i + 2] = '-'; 296 | } 297 | 298 | // We don't need the last '-' character 299 | return new String(chArray, 0, chArray.Length - 1); 300 | } 301 | 302 | // Converts an array of bytes into a String. 303 | public static String ToString(byte[] value) 304 | { 305 | if (value == null) 306 | throw new ArgumentNullException(nameof(value)); 307 | return ToString(value, 0, value.Length); 308 | } 309 | 310 | // Converts an array of bytes into a String. 311 | public static String ToString(byte[] value, int startIndex) 312 | { 313 | if (value == null) 314 | throw new ArgumentNullException(nameof(value)); 315 | return ToString(value, startIndex, value.Length - startIndex); 316 | } 317 | 318 | /*==================================ToBoolean=================================== 319 | **Action: Convert an array of bytes to a boolean value. We treat this array 320 | ** as if the first 4 bytes were an Int4 an operate on this value. 321 | **Returns: True if the Int4 value of the first 4 bytes is non-zero. 322 | **Arguments: value -- The byte array 323 | ** startIndex -- The position within the array. 324 | **Exceptions: See ToInt4. 325 | ==============================================================================*/ 326 | // Converts an array of bytes into a boolean. 327 | public static bool ToBoolean(byte[] value, int startIndex) 328 | { 329 | if (value == null) 330 | throw new ArgumentNullException(nameof(value)); 331 | if (startIndex < 0) 332 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_NeedNonNegNum"); 333 | if (startIndex > value.Length - 1) 334 | throw new ArgumentOutOfRangeException(nameof(startIndex), "ArgumentOutOfRange_Index"); 335 | 336 | return value[startIndex] != 0; 337 | } 338 | 339 | public static unsafe long DoubleToInt64Bits(double value) 340 | { 341 | return *((long*)&value); 342 | } 343 | 344 | public static unsafe double Int64BitsToDouble(long value) 345 | { 346 | return *((double*)&value); 347 | } 348 | } 349 | 350 | 351 | } -------------------------------------------------------------------------------- /FsControl.BaseLib/FsControl.BaseLib.csproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Debug 6 | AnyCPU 7 | {1B99DF98-65AC-4038-8BE5-E72B0882F420} 8 | Library 9 | Properties 10 | FsControl.BaseLib 11 | FsControl.BaseLib 12 | v4.0 13 | 512 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | bin\Debug\ 21 | DEBUG;TRACE 22 | prompt 23 | 4 24 | true 25 | 26 | 27 | pdbonly 28 | true 29 | bin\Release\ 30 | TRACE 31 | prompt 32 | 4 33 | true 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 56 | 57 | -------------------------------------------------------------------------------- /FsControl.BaseLib/Properties/AssemblyInfo.cs: -------------------------------------------------------------------------------- 1 | using System.Reflection; 2 | using System.Runtime.CompilerServices; 3 | using System.Runtime.InteropServices; 4 | 5 | // General Information about an assembly is controlled through the following 6 | // set of attributes. Change these attribute values to modify the information 7 | // associated with an assembly. 8 | [assembly: AssemblyTitle("FsControl.BaseLib")] 9 | [assembly: AssemblyDescription("")] 10 | [assembly: AssemblyConfiguration("")] 11 | [assembly: AssemblyCompany("Microsoft")] 12 | [assembly: AssemblyProduct("FsControl.BaseLib")] 13 | [assembly: AssemblyCopyright("Copyright © Microsoft 2013")] 14 | [assembly: AssemblyTrademark("")] 15 | [assembly: AssemblyCulture("")] 16 | 17 | // Setting ComVisible to false makes the types in this assembly not visible 18 | // to COM components. If you need to access a type in this assembly from 19 | // COM, set the ComVisible attribute to true on that type. 20 | [assembly: ComVisible(false)] 21 | 22 | // The following GUID is for the ID of the typelib if this project is exposed to COM 23 | [assembly: Guid("b1e53245-cee2-49e1-afda-50975cc29c69")] 24 | 25 | // Version information for an assembly consists of the following four values: 26 | // 27 | // Major Version 28 | // Minor Version 29 | // Build Number 30 | // Revision 31 | // 32 | // You can specify all the values or you can default the Build and Revision Numbers 33 | // by using the '*' as shown below: 34 | // [assembly: AssemblyVersion("1.0.*")] 35 | [assembly: AssemblyVersion("1.0.0.0")] 36 | [assembly: AssemblyFileVersion("1.0.0.0")] 37 | -------------------------------------------------------------------------------- /FsControl.Core/AssemblyInfo.fs: -------------------------------------------------------------------------------- 1 | module FsControl.AssemblyInfo 2 | 3 | open System.Reflection 4 | 5 | [] 6 | [] 7 | 8 | [] 9 | [] 10 | [] 11 | [] 12 | [] 13 | [] 14 | 15 | [] 16 | [] 17 | [] 18 | do() -------------------------------------------------------------------------------- /FsControl.Core/Collection.fs: -------------------------------------------------------------------------------- 1 | #nowarn "77" 2 | // Warn FS0077 -> Member constraints with the name 'get_Item' are given special status by the F# compiler as certain .NET types are implicitly augmented with this member. This may result in runtime failures if you attempt to invoke the member constraint from your own code. 3 | // Those .NET types are string and array but they are explicitely handled here. 4 | 5 | namespace FsControl 6 | 7 | open System 8 | open System.Text 9 | open System.Runtime.CompilerServices 10 | open System.Runtime.InteropServices 11 | open FsControl.Internals 12 | 13 | 14 | [] 15 | type Nth = 16 | inherit Default1 17 | []static member inline Nth (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.skip n |> Seq.head :'T 18 | []static member Nth (x:string , n, []impl:Nth ) = x.[n] 19 | []static member Nth (x:StringBuilder , n, []impl:Nth ) = x.ToString().[n] 20 | []static member Nth (x:'a [] , n, []impl:Nth ) = x.[n] : 'a 21 | []static member Nth (x:'a ResizeArray, n, []impl:Nth ) = x.[n] 22 | []static member Nth (x:list<'a> , n, []impl:Nth ) = x.[n] 23 | []static member Nth (x:'a Id , n, []impl:Nth ) = x.getValue 24 | 25 | static member inline Invoke (n:int) (source:'Collection'T) :'T = 26 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Nth: _*_*_ -> _) b, n, a) 27 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 28 | call (Unchecked.defaultof, source, n) 29 | 30 | [] 31 | type Skip = 32 | inherit Default1 33 | []static member inline Skip (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.skip n |> OfSeq.Invoke :'Foldable'T 34 | []static member Skip (x:string , n, []impl:Skip ) = x.[n..] 35 | []static member Skip (x:StringBuilder , n, []impl:Skip ) = new StringBuilder(x.ToString().[n..]) 36 | []static member Skip (x:'a [] , n, []impl:Skip ) = x.[n..] : 'a [] 37 | []static member Skip (x:'a ResizeArray, n, []impl:Skip ) = ResizeArray<'a> (Seq.skip n x) 38 | []static member Skip (x:list<'a> , n, []impl:Skip ) = n |> let rec listSkip lst = function 0 -> lst | n -> listSkip (List.tail lst) (n-1) in listSkip x 39 | []static member Skip (x:'a Id , n, []impl:Skip ) = x 40 | 41 | static member inline Invoke (n:int) (source:'Collection'T) :'Collection'T = 42 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Skip: _*_*_ -> _) b, n, a) 43 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 44 | call (Unchecked.defaultof, source, n) 45 | 46 | 47 | [] 48 | type Take = 49 | inherit Default1 50 | []static member inline Take (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.take n |> OfSeq.Invoke :'Foldable'T 51 | []static member Take (x:string , n, []impl:Take ) = x.[..n-1] 52 | []static member Take (x:StringBuilder , n, []impl:Take ) = new StringBuilder(x.ToString().[..n-1]) 53 | []static member Take (x:'a [] , n, []impl:Take ) = x.[..n-1] : 'a [] 54 | []static member Take (x:'a ResizeArray, n, []impl:Take ) = ResizeArray<'a> (Seq.take n x) 55 | []static member Take (x:list<'a> , n, []impl:Take ) = Seq.take n x |> Seq.toList 56 | []static member Take (x:'a Id , n, []impl:Take ) = x 57 | 58 | static member inline Invoke (n:int) (source:'Collection'T) :'Collection'T = 59 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Take: _*_*_ -> _) b, n, a) 60 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 61 | call (Unchecked.defaultof, source, n) 62 | 63 | 64 | [] 65 | type Drop = 66 | inherit Default1 67 | []static member inline Drop (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.drop n |> OfSeq.Invoke :'Foldable'T 68 | []static member Drop (x:string , n, []impl:Drop) = if n > 0 then (if x.Length > n then x.[n..] else "") else x 69 | []static member Drop (x:StringBuilder , n, []impl:Drop) = if n > 0 then (if x.Length > n then new StringBuilder(x.ToString().[n..]) else new StringBuilder()) else new StringBuilder(x.ToString()) 70 | []static member Drop (x:'a [] , n, []impl:Drop) = if n > 0 then (if x.Length > n then x.[n..] else [||]) else x : 'a [] 71 | []static member Drop (x:'a ResizeArray, n, []impl:Drop) = ResizeArray<'a> (Seq.drop n x) 72 | []static member Drop (x:list<'a> , n, []impl:Drop) = List.drop n x 73 | []static member Drop (x:'a Id , n, []impl:Drop) = x 74 | 75 | static member inline Invoke (n:int) (source:'Collection'T) :'Collection'T = 76 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Drop: _*_*_ -> _) b, n, a) 77 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 78 | call (Unchecked.defaultof, source, n) 79 | 80 | 81 | 82 | [] 83 | type Limit = 84 | inherit Default1 85 | []static member inline Limit (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.truncate n |> OfSeq.Invoke :'Foldable'T 86 | []static member Limit (x:string , n, []impl:Limit) = if n < 1 then "" elif n < x.Length then x.[..n-1] else x 87 | []static member Limit (x:StringBuilder , n, []impl:Limit) = new StringBuilder(x.ToString().[..n-1]) 88 | []static member Limit (x:'a [] , n, []impl:Limit) = if n < 1 then [||] elif n < x.Length then x.[..n-1] else x : 'a [] 89 | []static member Limit (x:'a ResizeArray, n, []impl:Limit) = ResizeArray<'a> (Seq.truncate n x) 90 | []static member Limit (x:list<'a> , n, []impl:Limit) = Seq.truncate n x |> Seq.toList 91 | []static member Limit (x:'a Id , n, []impl:Limit) = x 92 | 93 | static member inline Invoke (n:int) (source:'Collection'T) :'Collection'T = 94 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Limit: _*_*_ -> _) b, n, a) 95 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 96 | call (Unchecked.defaultof, source, n) 97 | 98 | 99 | 100 | type Choose = 101 | static member Choose (x:Id<'T> , f:_->'U option, []impl:Choose) = invalidOp "Choose on ID" :Id<'U> 102 | static member Choose (x:seq<'T> , f:_->'U option, []impl:Choose) = Seq.choose f x 103 | static member Choose (x:list<'T>, f:_->'U option, []impl:Choose) = List.choose f x 104 | static member Choose (x:'T [] , f:_->'U option, []impl:Choose) = Array.choose f x 105 | 106 | static member inline Invoke (chooser:'T->'U option) (source:'Collection'T) = 107 | let inline call_3 (a:^a, b:^b, c:^c, f) = ((^a or ^b or ^c) : (static member Choose: _*_*_ -> _) b, f, a) 108 | let inline call (a:'a, b:'b, c) = call_3 (a, b, Unchecked.defaultof<'r>, c) :'r 109 | call (Unchecked.defaultof, source, chooser) :'Collection'U 110 | 111 | 112 | [] 113 | type Distinct = 114 | inherit Default1 115 | []static member inline Distinct (x:'Foldable'T, []impl:Default1) = x |> ToSeq.Invoke |> Seq.distinct |> OfSeq.Invoke :'Foldable'T 116 | []static member Distinct (x:list<'T> , []impl:Distinct) = Seq.distinct x |> Seq.toList 117 | []static member Distinct (x:'T [] , []impl:Distinct) = Seq.distinct x |> Seq.toArray 118 | 119 | static member inline Invoke (source:'Collection'T) = 120 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Distinct: _*_ -> _) b, a) 121 | let inline call (a:'a, b:'b) = call_2 (a, b) 122 | call (Unchecked.defaultof, source) :'Collection'T 123 | 124 | 125 | type DistinctBy = 126 | inherit Default1 127 | static member inline DistinctBy (x:'Foldable'T, f, []impl:Default1 ) = x |> ToSeq.Invoke |> Seq.distinctBy f |> OfSeq.Invoke :'Foldable'T 128 | static member DistinctBy (x:list<'T> , f, []impl:DistinctBy) = Seq.distinctBy f x |> Seq.toList 129 | static member DistinctBy (x:'T [] , f, []impl:DistinctBy) = Seq.distinctBy f x |> Seq.toArray 130 | 131 | static member inline Invoke (projection:'T->'Key) (source:'Collection'T) = 132 | let inline call_2 (a:^a, b:^b, p) = ((^a or ^b) : (static member DistinctBy: _*_*_ -> _) b, p, a) 133 | let inline call (a:'a, b:'b, p) = call_2 (a, b, p) 134 | call (Unchecked.defaultof, source, projection) :'Collection'T 135 | 136 | 137 | type GroupBy = 138 | static member GroupBy (x:Id<'T> , f:'T->'Key, _:Id<'Key*Id<'T>> , []impl:GroupBy) = let a = Id.run x in Id.create (f a, x) 139 | static member GroupBy (x:seq<'T> , f:'T->'Key, _:seq<'Key*seq<'T>> , []impl:GroupBy) = Seq.groupBy f x 140 | static member GroupBy (x:list<'T>, f:'T->'Key, _:list<'Key*list<'T>>, []impl:GroupBy) = Seq.groupBy f x |> Seq.map (fun (x,y) -> x, Seq.toList y) |> Seq.toList 141 | static member GroupBy (x:'T [] , f:'T->'Key, _:('Key*('T [])) [] , []impl:GroupBy) = Seq.groupBy f x |> Seq.map (fun (x,y) -> x, Seq.toArray y) |> Seq.toArray 142 | 143 | static member inline Invoke (projection:'T->'Key) (source:'Collection'T) : 'Collection'KeyX'Collection'T = 144 | let inline call_3 (a:^a, b:^b, c:^c, p) = ((^a or ^b or ^c) : (static member GroupBy: _*_*_*_ -> _) b, p, c, a) 145 | let inline call (a:'a, b:'b, p) = call_3 (a, b, Unchecked.defaultof<'r>, p) :'r 146 | call (Unchecked.defaultof, source, projection) 147 | 148 | 149 | type ChunkBy = 150 | static member ChunkBy (x:Id<'T> , f:'T->'Key, _:Id<'Key*Id<'T>> , []impl:ChunkBy) = let a = Id.run x in Id.create (f a, x) 151 | static member ChunkBy (x:seq<'T> , f:'T->'Key, _:seq<'Key*seq<'T>> , []impl:ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, y :> _ seq) 152 | static member ChunkBy (x:list<'T>, f:'T->'Key, _:list<'Key*list<'T>>, []impl:ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, Seq.toList y) |> Seq.toList 153 | static member ChunkBy (x:'T [] , f:'T->'Key, _:('Key*('T [])) [] , []impl:ChunkBy) = Seq.chunkBy f x |> Seq.map (fun (x,y) -> x, Seq.toArray y) |> Seq.toArray 154 | 155 | static member inline Invoke (projection:'T->'Key) (source:'Collection'T) : 'Collection'KeyX'Collection'T = 156 | let inline call_3 (a:^a, b:^b, c:^c, p) = ((^a or ^b or ^c) : (static member ChunkBy: _*_*_*_ -> _) b, p, c, a) 157 | let inline call (a:'a, b:'b, p) = call_3 (a, b, Unchecked.defaultof<'r>, p) :'r 158 | call (Unchecked.defaultof, source, projection) 159 | 160 | 161 | [] 162 | type Length = 163 | inherit Default1 164 | []static member inline Length (x:'Foldable'T, []impl:Default1) = x |> ToSeq.Invoke |> Seq.length 165 | []static member Length (x:Id<'T> , []impl:Length) = 1 166 | []static member Length (x:seq<'T> , []impl:Length) = Seq.length x 167 | []static member Length (x:list<'T>, []impl:Length) = List.length x 168 | []static member Length (x:'T [] , []impl:Length) = Array.length x 169 | 170 | static member inline Invoke (source:'Collection'T) = 171 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Length: _*_ -> _) b, a) 172 | let inline call (a:'a, b:'b) = call_2 (a, b) 173 | call (Unchecked.defaultof, source) :int 174 | 175 | 176 | 177 | [] 178 | type Max = 179 | inherit Default1 180 | []static member inline Max (x:'Foldable'T, []impl:Default1) = x |> ToSeq.Invoke |> Seq.max :'T 181 | []static member Max (x:Id<'T> , []impl:Max) = x.getValue 182 | []static member Max (x:seq<'T> , []impl:Max) = Seq.max x 183 | []static member Max (x:list<'T>, []impl:Max) = List.max x 184 | []static member Max (x:'T [] , []impl:Max) = Array.max x 185 | 186 | static member inline Invoke (source:'Collection'T) = 187 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Max: _*_ -> _) b, a) 188 | let inline call (a:'a, b:'b) = call_2 (a, b) 189 | call (Unchecked.defaultof, source) :'T 190 | 191 | 192 | type MaxBy = 193 | inherit Default1 194 | static member inline MaxBy (x:'Foldable'T, f, []impl:Default1) = x |> ToSeq.Invoke |> Seq.maxBy f :'T 195 | static member MaxBy (x:Id<'T> , f:'T->'U, []impl:MaxBy) = x.getValue 196 | static member MaxBy (x:seq<'T> , f , []impl:MaxBy) = Seq.maxBy f x 197 | static member MaxBy (x:list<'T>, f , []impl:MaxBy) = List.maxBy f x 198 | static member MaxBy (x:'T [] , f , []impl:MaxBy) = Array.maxBy f x 199 | 200 | static member inline Invoke (projection:'T->'U) (source:'Collection'T) = 201 | let inline call_2 (a:^a, b:^b, f) = ((^a or ^b) : (static member MaxBy: _*_*_ -> _) b, f, a) 202 | let inline call (a:'a, b:'b, f) = call_2 (a, b, f) 203 | call (Unchecked.defaultof, source, projection) :'T 204 | 205 | 206 | [] 207 | type Min = 208 | inherit Default1 209 | []static member inline Min (x:'Foldable'T, []impl:Default1) = x |> ToSeq.Invoke |> Seq.min :'T 210 | []static member Min (x:Id<'T> , []impl:Min) = x.getValue 211 | []static member Min (x:seq<'T> , []impl:Min) = Seq.min x 212 | []static member Min (x:list<'T>, []impl:Min) = List.min x 213 | []static member Min (x:'T [] , []impl:Min) = Array.min x 214 | 215 | static member inline Invoke (source:'Collection'T) = 216 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Min: _*_ -> _) b, a) 217 | let inline call (a:'a, b:'b) = call_2 (a, b) 218 | call (Unchecked.defaultof, source) :'T 219 | 220 | 221 | type MinBy = 222 | inherit Default1 223 | static member inline MinBy (x:'Foldable'T, f, []impl:Default1) = x |> ToSeq.Invoke |> Seq.minBy f :'T 224 | static member MinBy (x:Id<'T> , f:'T->'U, []impl:MinBy) = x.getValue 225 | static member MinBy (x:seq<'T> , f , []impl:MinBy) = Seq.minBy f x 226 | static member MinBy (x:list<'T>, f , []impl:MinBy) = List.minBy f x 227 | static member MinBy (x:'T [] , f , []impl:MinBy) = Array.minBy f x 228 | 229 | static member inline Invoke (projection:'T->'U) (source:'Collection'T) = 230 | let inline call_2 (a:^a, b:^b, f) = ((^a or ^b) : (static member MinBy: _*_*_ -> _) b, f, a) 231 | let inline call (a:'a, b:'b, f) = call_2 (a, b, f) 232 | call (Unchecked.defaultof, source, projection) :'T 233 | 234 | 235 | [] 236 | type Replace = 237 | inherit Default1 238 | static member inline Replace (x:'Collection , o:'Collection , n:'Collection , []impl:Default1) = x |> ToSeq.Invoke |> Seq.replace (ToSeq.Invoke o) (ToSeq.Invoke n) |> OfSeq.Invoke : 'Collection 239 | static member Replace (x:Id<'T> , o:Id<'T> , n:Id<'T> , []impl:Default1) = if x = o then n else x 240 | []static member Replace (x:list<'T> , o:list<'T> , n:list<'T> , []impl:Replace ) = x |> List.toSeq |> Seq.replace o n |> Seq.toList 241 | []static member Replace (x:'T [] , o:'T [] , n:'T [] , []impl:Replace ) = x |> Array.toSeq |> Seq.replace o n |> Seq.toArray 242 | []static member Replace (x:string , o:string , n:string , []impl:Replace ) = if o.Length = 0 then x else x.Replace(o, n) 243 | []static member Replace (x:StringBuilder, o:StringBuilder, n:StringBuilder, []impl:Replace ) = if o.Length = 0 then x else StringBuilder(x.ToString().Replace(o.ToString(), n.ToString())) 244 | 245 | static member inline Invoke (o:'Collection) (n:'Collection) (source:'Collection) = 246 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Replace: _*_*_*_ -> _) b, o, n, a) 247 | let inline call (a:'a, b:'b) = call_2 (a, b) 248 | call (Unchecked.defaultof, source) :'Collection 249 | 250 | 251 | [] 252 | type Rev = 253 | inherit Default1 254 | []static member inline Rev (x:'Foldable'T, []impl:Default1) = x |> ToSeq.Invoke |> Seq.toArray |> Array.rev |> Array.toSeq |> OfSeq.Invoke :'Foldable'T 255 | []static member Rev (x:list<'a> , []impl:Rev ) = List.rev x 256 | []static member Rev (x:'a [] , []impl:Rev ) = Array.rev x 257 | 258 | static member inline Invoke (source:'Collection'T) = 259 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Rev: _*_ -> _) b, a) 260 | let inline call (a:'a, b:'b) = call_2 (a, b) 261 | call (Unchecked.defaultof, source) :'Collection'T 262 | 263 | 264 | type Scan = 265 | static member Scan (x:Id<'T> , f ,z:'S, []output:Id<'S> , []impl:Scan) = Id.create (f z x.getValue) 266 | static member Scan (x:seq<'T> , f ,z:'S, []output:seq<'S> , []impl:Scan) = Seq.scan f z x 267 | static member Scan (x:list<'T>, f ,z:'S, []output:list<'S>, []impl:Scan) = List.scan f z x 268 | static member Scan (x:'T [] , f ,z:'S, []output:'S [] , []impl:Scan) = Array.scan f z x 269 | 270 | static member inline Invoke (folder:'State'->'T->'State) (state:'State) (source:'Collection'T) = 271 | let inline call_3 (a:^a, b:^b, c:^c, f, z) = ((^a or ^b or ^c) : (static member Scan: _*_*_*_*_ -> _) b, f, z, c, a) 272 | let inline call (a:'a, b:'b, f, z) = call_3 (a, b, Unchecked.defaultof<'r>, f, z) :'r 273 | call (Unchecked.defaultof, source, folder, state) :'Collection'State 274 | 275 | 276 | [] 277 | type Sort = 278 | inherit Default1 279 | []static member inline Sort (x:'Foldable'T, []impl:Default2) = x |> ToSeq.Invoke |> Seq.sort |> OfSeq.Invoke :'Foldable'T 280 | []static member inline Sort (x:^Foldable'T, []impl:Default1) = ((^Foldable'T) : (static member Sort: _->_) x) : ^Foldable'T 281 | []static member Sort (x:list<'a> , []impl:Sort ) = List.sort x 282 | []static member Sort (x:'a [] , []impl:Sort ) = Array.sort x 283 | 284 | static member inline Invoke (source:'Collection'T) = 285 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Sort: _*_ -> _) b, a) 286 | let inline call (a:'a, b:'b) = call_2 (a, b) 287 | call (Unchecked.defaultof, source) :'Collection'T 288 | 289 | 290 | type SortBy = 291 | inherit Default1 292 | 293 | static member SortBy (x:list<'a> , f , []impl:SortBy ) = List.sortBy f x 294 | static member SortBy (x:'a [] , f , []impl:SortBy ) = Array.sortBy f x 295 | 296 | static member inline Invoke (projection:'T->'Key) (source:'Collection'T) : 'Collection'T = 297 | let inline call_2 (a:^a, b:^b, f) = ((^a or ^b) : (static member SortBy: _*_*_ -> _) b, f, a) 298 | let inline call (a:'a, b:'b, f) = call_2 (a, b, f) 299 | call (Unchecked.defaultof, source, projection) 300 | static member inline InvokeOnInstance (projection:'T->'Key) (source:'Collection'T) : 'Collection'T = (^Collection'T : (static member SortBy: _*_->_) projection, source) : ^Collection'T 301 | 302 | static member inline SortBy (x:'Foldable'T, f , []impl:Default2) = x |> ToSeq.Invoke |> Seq.sortBy f |> OfSeq.Invoke :'Foldable'T 303 | static member inline SortBy (x:^Foldable'T, f , []impl:Default1) = ((^Foldable'T) : (static member SortBy: _*_->_) f, x) : ^Foldable'T 304 | static member inline SortBy (_ : ^t when ^t : null and ^t : struct, f : 'T -> 'U, mthd : Default1) = id 305 | 306 | 307 | [] 308 | type Split = 309 | inherit Default1 310 | []static member Split (x:seq<'T> , e:seq> , []impl:Split) = x |> Seq.split StringSplitOptions.None e 311 | []static member Split (x:list<'T> , e:seq> , []impl:Split) = x |> List.toSeq |> Seq.split StringSplitOptions.None e |> Seq.map Seq.toList 312 | []static member Split (x:'T [] , e:seq<'T []> , []impl:Split) = x |> Array.toSeq |> Seq.split StringSplitOptions.None e |> Seq.map Seq.toArray 313 | []static member Split (x:string , e:seq , []impl:Split) = x.Split(Seq.toArray e, StringSplitOptions.None) :> seq<_> 314 | []static member Split (x:StringBuilder, e:seq, []impl:Split) = x.ToString().Split(e |> Seq.map (fun x -> x.ToString()) |> Seq.toArray, StringSplitOptions.None) |> Array.map StringBuilder :> seq<_> 315 | 316 | static member inline Invoke (sep:seq<'Collection>) (source:'Collection) = 317 | let inline call_2 (a:^a, b:^b, s) = ((^a or ^b) : (static member Split: _*_*_ -> _) b, s, a) 318 | let inline call (a:'a, b:'b, s) = call_2 (a, b, s) 319 | call (Unchecked.defaultof, source,sep) :seq<'Collection> 320 | 321 | 322 | [] 323 | type Unzip = 324 | []static member Unzip (source:seq<'T * 'U> , []output:seq<'T> * seq<'U> , []impl:Unzip) = Seq.map fst source, Seq.map snd source 325 | []static member Unzip (source:list<'T * 'U>, []output:list<'T> * list<'U>, []impl:Unzip) = List.unzip source 326 | []static member Unzip (source:('T * 'U) [] , []output:'T [] * 'U [] , []impl:Unzip) = Array.unzip source 327 | 328 | static member inline Invoke (source:'``Collection<'T1 * 'T2>``) = 329 | let inline call_3 (a:^a, b:^b, d:^d) = ((^a or ^b or ^d) : (static member Unzip: _*_*_ -> _) b, d, a) 330 | let inline call (a:'a, b:'b) = call_3 (a, b, Unchecked.defaultof<'r>) :'r 331 | call (Unchecked.defaultof, source) :'``Collection<'T1>`` * '``Collection<'T2>`` 332 | 333 | 334 | [] 335 | type Zip = 336 | []static member Zip (x:Id<'T> , y:Id<'U> , []output:Id<'T*'U> , []impl:Zip) = Id.create(x.getValue,y.getValue) 337 | []static member Zip (x:seq<'T> , y:seq<'U> , []output:seq<'T*'U> , []impl:Zip) = Seq.zip x y 338 | []static member Zip (x:list<'T>, y:list<'U>, []output:list<'T*'U>, []impl:Zip) = List.zip x y 339 | []static member Zip (x:'T [] , y:'U [] , []output:('T*'U) [] , []impl:Zip) = Array.zip x y 340 | 341 | static member inline Invoke (source1:'Collection'T1) (source2:'Collection'T2) = 342 | let inline call_4 (a:^a, b:^b, c:^c, d:^d) = ((^a or ^b or ^c or ^d) : (static member Zip: _*_*_*_ -> _) b, c, d, a) 343 | let inline call (a:'a, b:'b, c:'c) = call_4 (a, b, c, Unchecked.defaultof<'r>) :'r 344 | call (Unchecked.defaultof, source1, source2) :'Collection'T1'T2 -------------------------------------------------------------------------------- /FsControl.Core/Converter.fs: -------------------------------------------------------------------------------- 1 | #nowarn "77" 2 | // Warn FS0077 -> Member constraints with the name 'op_Explicit' are given special status by the F# compiler as certain .NET types are implicitly augmented with this member. This may result in runtime failures if you attempt to invoke the member constraint from your own code. 3 | // But all simulated types are being handled so here Explicit is SAFE from runtime errors. 4 | 5 | namespace FsControl 6 | 7 | open System 8 | open System.Runtime.CompilerServices 9 | open System.Runtime.InteropServices 10 | open System.Collections.Generic 11 | open System.Text 12 | open Microsoft.FSharp.Quotations 13 | open Microsoft.FSharp.Core.Printf 14 | open FsControl.BaseLib 15 | open FsControl.Internals 16 | open FsControl.Internals.Prelude 17 | open System.Numerics 18 | 19 | 20 | type Explicit = 21 | inherit Default1 22 | static member inline Explicit (_:'R , _:Default1) = fun (x : ^t) -> ((^R or ^t) : (static member op_Explicit : ^t -> ^R) x) 23 | static member inline Explicit (_:^t when ^t: null and ^t: struct, _:Default1) = () 24 | static member inline Explicit (_:byte , _:Explicit) = fun x -> byte x 25 | static member inline Explicit (_:sbyte , _:Explicit) = fun x -> sbyte x 26 | static member inline Explicit (_:int16 , _:Explicit) = fun x -> int16 x 27 | static member inline Explicit (_:uint16 , _:Explicit) = fun x -> uint16 x 28 | static member inline Explicit (_:int32 , _:Explicit) = fun x -> int x 29 | static member inline Explicit (_:uint32 , _:Explicit) = fun x -> uint32 x 30 | static member inline Explicit (_:int64 , _:Explicit) = fun x -> int64 x 31 | static member inline Explicit (_:uint64 , _:Explicit) = fun x -> uint64 x 32 | static member inline Explicit (_:nativeint , _:Explicit) = fun x -> nativeint (int x) 33 | static member inline Explicit (_:unativeint, _:Explicit) = fun x -> unativeint (int x) 34 | static member inline Explicit (_:float , _:Explicit) = fun x -> float x 35 | static member inline Explicit (_:float32 , _:Explicit) = fun x -> float32 x 36 | static member inline Explicit (_:decimal , _:Explicit) = fun x -> decimal x 37 | static member inline Explicit (_:char , _:Explicit) = fun x -> char x 38 | 39 | static member inline Invoke value:'T = 40 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Explicit: _*_ -> _) b, a) 41 | let inline call (a:'a) = fun (x:'x) -> call_2 (a, Unchecked.defaultof<'r>) x :'r 42 | call Unchecked.defaultof value 43 | 44 | type OfBytes = 45 | static member OfBytes (_:bool , _:OfBytes) = fun (x, i, _) -> BitConverter.ToBoolean(x, i) 46 | static member OfBytes (_:char , _:OfBytes) = fun (x, i, e) -> BitConverter.ToChar (x, i, e) 47 | static member OfBytes (_:float , _:OfBytes) = fun (x, i, e) -> BitConverter.ToDouble (x, i, e) 48 | static member OfBytes (_: int16 , _:OfBytes) = fun (x, i, e) -> BitConverter.ToInt16 (x, i, e) 49 | static member OfBytes (_: int , _:OfBytes) = fun (x, i, e) -> BitConverter.ToInt32 (x, i, e) 50 | static member OfBytes (_:int64 , _:OfBytes) = fun (x, i, e) -> BitConverter.ToInt64 (x, i, e) 51 | static member OfBytes (_:float32, _:OfBytes) = fun (x, i, e) -> BitConverter.ToSingle (x, i, e) 52 | static member OfBytes (_:string , _:OfBytes) = fun (x, i, _) -> BitConverter.ToString (x, i) 53 | static member OfBytes (_:uint16 , _:OfBytes) = fun (x, i, e) -> BitConverter.ToUInt16 (x, i, e) 54 | static member OfBytes (_:uint32 , _:OfBytes) = fun (x, i, e) -> BitConverter.ToUInt32 (x, i, e) 55 | static member OfBytes (_:uint64 , _:OfBytes) = fun (x, i, e) -> BitConverter.ToUInt64 (x, i, e) 56 | 57 | static member inline Invoke (isLtEndian:bool) (startIndex:int) (value:byte[]) = 58 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member OfBytes: _*_ -> _) b, a) 59 | let inline call (a:'a) = fun (x:'x) -> call_2 (a, Unchecked.defaultof<'r>) x :'r 60 | call Unchecked.defaultof (value, startIndex, isLtEndian) 61 | 62 | 63 | [] 64 | type ToBytes = 65 | []static member ToBytes (x:bool , e, _:ToBytes) = BitConverter.GetBytes(x) 66 | []static member ToBytes (x:char , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 67 | []static member ToBytes (x:float , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 68 | []static member ToBytes (x: int16 , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 69 | []static member ToBytes (x: int , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 70 | []static member ToBytes (x:int64 , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 71 | []static member ToBytes (x:float32, e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 72 | []static member ToBytes (x:string , e, _:ToBytes) = Array.map byte (x.ToCharArray()) 73 | []static member ToBytes (x:uint16 , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 74 | []static member ToBytes (x:uint32 , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 75 | []static member ToBytes (x:uint64 , e, _:ToBytes) = BitConverter.GetBytes(x, BitConverter.IsLittleEndian = e) 76 | 77 | static member inline Invoke (isLittleEndian:bool) value :byte[] = 78 | let inline call_2 (a:^a, b:^b, e) = ((^a or ^b) : (static member ToBytes: _*_*_ -> _) b, e, a) 79 | let inline call (a:'a, b:'b, e) = call_2 (a, b, e) 80 | call (Unchecked.defaultof, value, isLittleEndian) 81 | 82 | 83 | open System.Globalization 84 | 85 | type TryParse = 86 | static member inline TryParse (_:'t option, _:TryParse) = fun x -> 87 | let mutable r = Unchecked.defaultof< ^R> 88 | if (^R: (static member TryParse: _ * _ -> _) (x, &r)) then Some r else None 89 | 90 | static member TryParse (_:string option, _:TryParse) = fun x -> Some x :option 91 | static member TryParse (_:StringBuilder option, _:TryParse) = fun x -> Some (new StringBuilder(x:string)) :option 92 | 93 | static member inline Invoke (value:string) = 94 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member TryParse: _*_ -> _) b, a) 95 | let inline call (a:'a) = fun (x:'x) -> call_2 (a, Unchecked.defaultof<'r>) x :'r 96 | call Unchecked.defaultof value 97 | 98 | 99 | type Parse = 100 | inherit Default1 101 | static member inline Parse (_:^R , _:Default1) = fun (x:string) -> (^R: (static member Parse: _ -> ^R) x) 102 | static member inline Parse (_:^R , _:Parse ) = fun (x:string) -> (^R: (static member Parse: _ * _ -> ^R) (x, CultureInfo.InvariantCulture)) 103 | #if NOTNET35 104 | static member Parse (_:'T when 'T : enum<_>, _:Parse ) = fun x -> 105 | (match Enum.TryParse(x) with 106 | | (true, v) -> v 107 | | _ -> invalidArg "value" ("Requested value '" + x + "' was not found.") 108 | ):'enum 109 | #endif 110 | static member Parse (_:bool , _:Parse) = fun x -> Boolean.Parse(x) 111 | static member Parse (_:char , _:Parse) = fun x -> Char .Parse(x) 112 | static member Parse (_:string , _:Parse) = id :string->_ 113 | static member Parse (_:StringBuilder, _:Parse) = fun x -> new StringBuilder(x:string) 114 | 115 | static member inline Invoke (value:string) = 116 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Parse: _*_ -> _) b, a) 117 | let inline call (a:'a) = fun (x:'x) -> call_2 (a, Unchecked.defaultof<'r>) x :'r 118 | call Unchecked.defaultof value 119 | 120 | 121 | type ToString = 122 | static member ToString (x:bool , _:ToString) = fun (k:CultureInfo) -> x.ToString k 123 | static member ToString (x:char , _:ToString) = fun (k:CultureInfo) -> x.ToString k 124 | static member ToString (x:byte , _:ToString) = fun (k:CultureInfo) -> x.ToString k 125 | static member ToString (x:sbyte , _:ToString) = fun (k:CultureInfo) -> x.ToString k 126 | static member ToString (x:float , _:ToString) = fun (k:CultureInfo) -> x.ToString k 127 | static member ToString (x:int16 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 128 | static member ToString (x:int , _:ToString) = fun (k:CultureInfo) -> x.ToString k 129 | static member ToString (x:int64 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 130 | static member ToString (x:float32 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 131 | static member ToString (x:string , _:ToString) = fun (_:CultureInfo) -> if isNull x then "null" else x 132 | static member ToString (x:Uri , _:ToString) = fun (_:CultureInfo) -> if isNull x then "null" else x.ToString() 133 | static member ToString (x:Id0 , _:ToString) = fun (_:CultureInfo) -> x.getValue 134 | static member ToString (x:uint16 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 135 | static member ToString (x:uint32 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 136 | static member ToString (x:uint64 , _:ToString) = fun (k:CultureInfo) -> x.ToString k 137 | static member ToString (x:decimal , _:ToString) = fun (k:CultureInfo) -> x.ToString k 138 | static member ToString (x:DateTime , _:ToString) = fun (k:CultureInfo) -> x.ToString k 139 | static member ToString (x:DateTimeOffset, _:ToString) = fun (k:CultureInfo) -> x.ToString k 140 | static member ToString (x:StringBuilder , _:ToString) = fun (_:CultureInfo) -> if isNull x then "null" else x.ToString() 141 | 142 | static member inline Invoke (culture:CultureInfo) value : string = 143 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member ToString: _*_ -> _) b, a) 144 | let inline call (a:'a, b:'b) = fun (x:'x) -> call_2 (a, b) x 145 | call (Unchecked.defaultof, value) culture 146 | 147 | 148 | type ToString with 149 | static member inline ToString (KeyValue(a,b), _:ToString) = fun (k:CultureInfo) -> "(" + ToString.Invoke k a + ", " + ToString.Invoke k b + ")" 150 | static member inline ToString ((a,b) , _:ToString) = fun (k:CultureInfo) -> "(" + ToString.Invoke k a + ", " + ToString.Invoke k b + ")" 151 | static member inline ToString ((a,b,c) , _:ToString) = fun (k:CultureInfo) -> "(" + ToString.Invoke k a + ", " + ToString.Invoke k b + ", " + ToString.Invoke k c + ")" 152 | static member inline ToString ((a,b,c,d) , _:ToString) = fun (k:CultureInfo) -> "(" + ToString.Invoke k a + ", " + ToString.Invoke k b + ", " + ToString.Invoke k c + ", " + ToString.Invoke k d + ")" 153 | static member inline ToString ((a,b,c,d,e) , _:ToString) = fun (k:CultureInfo) -> "(" + ToString.Invoke k a + ", " + ToString.Invoke k b + ", " + ToString.Invoke k c + ", " + ToString.Invoke k d + ", " + ToString.Invoke k e + ")" 154 | 155 | 156 | type ToString with 157 | static member inline internal seqToString (k:CultureInfo) sepOpen sepClose x (b: StringBuilder) = 158 | let inline append (s:string) = b.Append s |> ignore 159 | append sepOpen 160 | let withSemiColons = Seq.intersperse "; " (Seq.map (ToString.Invoke k) x) 161 | Seq.iter append withSemiColons 162 | append sepClose 163 | ToString.Invoke k b 164 | 165 | type ToString with static member inline ToString (x:_ list, _:ToString) = fun (k:CultureInfo) -> 166 | let b = StringBuilder() 167 | ToString.seqToString k "[" "]" x b 168 | 169 | type ToString with static member inline ToString (x:_ array, _:ToString) = fun (k:CultureInfo) -> 170 | let b = StringBuilder() 171 | ToString.seqToString k "[|" "|]" x b 172 | 173 | type ToString with 174 | static member inline ToString (x:_ ResizeArray, _:ToString) = fun (k:CultureInfo) -> 175 | let b = StringBuilder() 176 | b.Append "ResizeArray " |> ignore 177 | ToString.seqToString k "[" "]" x b 178 | static member ToString (x:Expr<_> , _:ToString) = fun (k:CultureInfo) -> x.ToString() 179 | 180 | type ToString with static member inline ToString (x:_ seq, _:ToString) = fun (k:CultureInfo) -> 181 | let b = StringBuilder() 182 | b.Append "seq " |> ignore 183 | ToString.seqToString k "[" "]" x b 184 | 185 | type ToString with static member inline ToString (x:_ ICollection, _:ToString) = fun (k:CultureInfo) -> 186 | ToString.Invoke k (x :> _ seq) 187 | 188 | type ToString with static member inline ToString (x:_ IList , _:ToString) = fun (k:CultureInfo) -> 189 | ToString.Invoke k (x :> _ seq) 190 | 191 | type ToString with static member inline ToString (x:Map<_,_> , _:ToString) = fun (k:CultureInfo) -> 192 | let b = StringBuilder() 193 | b.Append "map " |> ignore 194 | ToString.seqToString k "[" "]" x b 195 | 196 | type ToString with 197 | static member inline ToString (x:Dictionary<_,_>, _:ToString) = fun (k:CultureInfo) -> 198 | ToString.Invoke k (x :> seq>) 199 | 200 | static member inline ToString (x:_ Set, _, _:ToString) = fun (k:CultureInfo) -> 201 | let b = StringBuilder() 202 | b.Append "set " |> ignore 203 | ToString.seqToString k "[" "]" x b 204 | 205 | type ToString with static member inline ToString (x:IDictionary<_,_>, _:ToString) = fun (k:CultureInfo) -> 206 | ToString.Invoke k (x :> seq>) 207 | 208 | type ToString with static member inline ToString (x:_ option, _:ToString) = fun (k:CultureInfo) -> 209 | match x with 210 | | Some a -> "Some " + ToString.Invoke k a 211 | | None -> "None" 212 | 213 | type ToString with static member inline ToString (x:Choice<_,_>, _:ToString) = fun (k:CultureInfo) -> 214 | match x with 215 | | Choice1Of2 a -> "Choice1Of2 " + ToString.Invoke k a 216 | | Choice2Of2 b -> "Choice2Of2 " + ToString.Invoke k b 217 | 218 | type ToString with static member inline ToString (x:Choice<_,_,_>, _:ToString) = fun (k:CultureInfo) -> 219 | match x with 220 | | Choice1Of3 a -> "Choice1Of3 " + ToString.Invoke k a 221 | | Choice2Of3 b -> "Choice2Of3 " + ToString.Invoke k b 222 | | Choice3Of3 c -> "Choice3Of3 " + ToString.Invoke k c 223 | 224 | type ToString with static member inline ToString (x:Choice<_,_,_,_>, _:ToString) = fun (k:CultureInfo) -> 225 | match x with 226 | | Choice1Of4 a -> "Choice1Of4 " + ToString.Invoke k a 227 | | Choice2Of4 b -> "Choice2Of4 " + ToString.Invoke k b 228 | | Choice3Of4 c -> "Choice3Of4 " + ToString.Invoke k c 229 | | Choice4Of4 d -> "Choice4Of4 " + ToString.Invoke k d 230 | 231 | 232 | type ToString with static member inline ToString (x:Choice<_,_,_,_,_>, _:ToString) = fun (k:CultureInfo) -> 233 | match x with 234 | | Choice1Of5 a -> "Choice1Of5 " + ToString.Invoke k a 235 | | Choice2Of5 b -> "Choice2Of5 " + ToString.Invoke k b 236 | | Choice3Of5 c -> "Choice3Of5 " + ToString.Invoke k c 237 | | Choice4Of5 d -> "Choice4Of5 " + ToString.Invoke k d 238 | | Choice5Of5 e -> "Choice5Of5 " + ToString.Invoke k e 239 | 240 | type ToString with static member inline ToString (x:Choice<_,_,_,_,_,_>, _:ToString) = fun (k:CultureInfo) -> 241 | match x with 242 | | Choice1Of6 a -> "Choice1Of6 " + ToString.Invoke k a 243 | | Choice2Of6 b -> "Choice2Of6 " + ToString.Invoke k b 244 | | Choice3Of6 c -> "Choice3Of6 " + ToString.Invoke k c 245 | | Choice4Of6 d -> "Choice4Of6 " + ToString.Invoke k d 246 | | Choice5Of6 e -> "Choice5Of6 " + ToString.Invoke k e 247 | | Choice6Of6 f -> "Choice6Of6 " + ToString.Invoke k f 248 | 249 | type ToString with static member inline ToString (x:Choice<_,_,_,_,_,_,_>, _:ToString) = fun (k:CultureInfo) -> 250 | match x with 251 | | Choice1Of7 a -> "Choice1Of7 " + ToString.Invoke k a 252 | | Choice2Of7 b -> "Choice2Of7 " + ToString.Invoke k b 253 | | Choice3Of7 c -> "Choice3Of7 " + ToString.Invoke k c 254 | | Choice4Of7 d -> "Choice4Of7 " + ToString.Invoke k d 255 | | Choice5Of7 e -> "Choice5Of7 " + ToString.Invoke k e 256 | | Choice6Of7 f -> "Choice6Of7 " + ToString.Invoke k f 257 | | Choice7Of7 g -> "Choice7Of7 " + ToString.Invoke k g -------------------------------------------------------------------------------- /FsControl.Core/FsControl.Core.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | Release 6 | AnyCPU 7 | 2.0 8 | 92eb1018-06de-4300-8daa-047f4f53c2b9 9 | Library 10 | FsControl 11 | FsControl 12 | v4.0 13 | FsControl 14 | 15 | 16 | 17 | true 18 | full 19 | false 20 | false 21 | bin\Debug\ 22 | DEBUG;TRACE 23 | 3 24 | bin\Debug\FsControl.XML 25 | --staticlink:FsControl.BaseLib 26 | 27 | 28 | pdbonly 29 | true 30 | true 31 | bin\Release\ 32 | TRACE 33 | 3 34 | bin\Release\FsControl.XML 35 | --staticlink:FsControl.BaseLib 36 | 37 | 38 | $(DefineConstants);NET35 39 | 40 | 41 | $(DefineConstants);NOTNET35 42 | 43 | 44 | 11 45 | 46 | 47 | 48 | 49 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 50 | 51 | 52 | 53 | 54 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | ..\..\lib\FSharp\Net20\FSharp.Core.dll 82 | 83 | 84 | ..\..\lib\FSharp\FSharp.Core.dll 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | FsControl.BaseLib 94 | {1b99df98-65ac-4038-8be5-e72b0882f420} 95 | False 96 | 97 | 98 | 105 | -------------------------------------------------------------------------------- /FsControl.Core/FsControl.Core.nuspec: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | FsControl 5 | $version$ 6 | $title$ 7 | Gusty 8 | Gusty 9 | http://www.apache.org/licenses/ 10 | https://github.com/gmpl/FsControl 11 | true 12 | FsControl is an overload library for F#. 13 | Version 2 (Pre Release) 14 | Copyright 2012-2014 15 | FSharp Applicative Monad MonadTransformer Arrow Overloading 16 | 17 | -------------------------------------------------------------------------------- /FsControl.Core/Indexable.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open System 4 | open System.Runtime.CompilerServices 5 | open System.Runtime.InteropServices 6 | open System.Text 7 | open FsControl.Internals 8 | 9 | 10 | [] 11 | type Item = 12 | inherit Default1 13 | []static member inline Item (x:'Foldable'T , n, []impl:Default1) = x |> ToSeq.Invoke |> Seq.skip n |> Seq.head :'T 14 | []static member Item (x:string , n, []impl:Item ) = x.[n] 15 | []static member Item (x:StringBuilder , n, []impl:Item ) = x.ToString().[n] 16 | []static member Item (x:'a [] , n, []impl:Item ) = x.[n] : 'a 17 | []static member Item (x:'a [,] , (i,j), []impl:Item) = x.[i,j] : 'a 18 | []static member Item (x:'a ResizeArray, n, []impl:Item ) = x.[n] 19 | []static member Item (x:list<'a> , n, []impl:Item ) = x.[n] 20 | []static member Item (x:Map<'K,'T> , k, []impl:Item) = x.[k] : 'T 21 | 22 | static member inline Invoke (n:'K) (source:'``Indexed<'T>``) :'T = 23 | let inline call_2 (a:^a, b:^b, n) = ((^a or ^b) : (static member Item: _*_*_ -> _) b, n, a) 24 | let inline call (a:'a, b:'b, n) = call_2 (a, b, n) 25 | call (Unchecked.defaultof, source, n) 26 | 27 | type MapIndexed = 28 | static member MapIndexed (x:Id<'T> , f:_->'T->'U , []impl:MapIndexed) = f () x.getValue 29 | static member MapIndexed (x:seq<'T> , f , []impl:MapIndexed) = Seq.mapi f x 30 | static member MapIndexed (x:list<'T> , f , []impl:MapIndexed) = List.mapi f x 31 | static member MapIndexed (x:'T [] , f , []impl:MapIndexed) = Array.mapi f x 32 | static member MapIndexed ((k:'K, a:'T), f , []impl:MapIndexed) = (k, ((f k a):'U)) 33 | static member MapIndexed (g , f:'K->'T->'U, []impl:MapIndexed) = fun x -> f x (g x) 34 | static member MapIndexed (x:Map<'K,'T>, f , []impl:MapIndexed) = Map.map f x :Map<'K,'U> 35 | 36 | static member inline Invoke (mapping:'K->'T->'U) (source:'Indexable'T) = 37 | let inline call_3 (a:^a, b:^b, c:^c, f) = ((^a or ^b or ^c) : (static member MapIndexed: _*_*_ -> _) b, f, a) 38 | let inline call (a:'a, b:'b, f) = call_3 (a, b, Unchecked.defaultof<'r>, f) :'r 39 | call (Unchecked.defaultof, source, mapping) :'Indexable'U 40 | 41 | 42 | type IterateIndexed = 43 | static member IterateIndexed (x:Id<'T> , f:_->'T->unit, []impl:IterateIndexed) = f () x.getValue 44 | static member IterateIndexed (x:seq<'T> , f , []impl:IterateIndexed) = Seq.iteri f x 45 | static member IterateIndexed (x:list<'T>, f , []impl:IterateIndexed) = List.iteri f x 46 | static member IterateIndexed (x:'T [] , f , []impl:IterateIndexed) = Array.iteri f x 47 | static member IterateIndexed (x:Map<'K,'T>, f , []impl:IterateIndexed) = Map.iter f x 48 | 49 | static member inline Invoke (action:'K->'T->unit) (source:'Indexable'T) = 50 | let inline call_2 (a:^a, b:^b, f) = ((^a or ^b) : (static member IterateIndexed: _*_*_ -> _) b, f, a) 51 | let inline call (a:'a, b:'b, f) = call_2 (a, b, f) 52 | call (Unchecked.defaultof, source, action) :unit 53 | 54 | 55 | 56 | type FoldIndexed = 57 | static member FoldIndexed (x:seq<_> , f, z, impl:FoldIndexed ) = x |> Seq.fold (fun (p, i) t -> (f p i t, i + 1)) (z, 0) |> fst 58 | static member FoldIndexed (x:list<_> , f, z, impl:FoldIndexed ) = x |> List.fold (fun (p, i) t -> (f p i t, i + 1)) (z, 0) |> fst 59 | static member FoldIndexed (x: _ [] , f, z, impl:FoldIndexed ) = x |> Array.fold (fun (p, i) t -> (f p i t, i + 1)) (z, 0) |> fst 60 | static member FoldIndexed (x:Map<'k,'t>, f, z, impl:FoldIndexed ) = Map.fold f z 61 | 62 | static member inline Invoke (folder:'State->'Key->'T->'State) (state:'State) (foldable:'Foldable'T) :'State = 63 | let inline call_2 (a:^a, b:^b, f, z) = ((^a or ^b) : (static member FoldIndexed: _*_*_*_ -> _) b, f, z, a) 64 | let inline call (a:'a, b:'b, f, z) = call_2 (a, b, f, z) 65 | call (Unchecked.defaultof, foldable, folder, state) 66 | 67 | type TraverseIndexed = 68 | static member inline TraverseIndexed ((k:'K, a:'T), f , []output:'R, []impl:TraverseIndexed) :'R = Map.Invoke ((fun x y -> (x, y)) k) (f k a) 69 | static member inline TraverseIndexed (a:Tuple<_> , f , []output:'R, []impl:TraverseIndexed) :'R = Map.Invoke Tuple (f () a.Item1) 70 | 71 | static member inline Invoke f t = 72 | let inline call_3 (a:^a, b:^b, c:^c, f) = ((^a or ^b or ^c) : (static member TraverseIndexed: _*_*_*_ -> _) b, f, c, a) 73 | let inline call (a:'a, b:'b, f) = call_3 (a, b, Unchecked.defaultof<'r>, f) :'r 74 | call (Unchecked.defaultof, t, f) -------------------------------------------------------------------------------- /FsControl.Core/Internals.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl.Internals 2 | 3 | type Default5 = class end 4 | type Default4 = class inherit Default5 end 5 | type Default3 = class inherit Default4 end 6 | type Default2 = class inherit Default3 end 7 | type Default1 = class inherit Default2 end 8 | 9 | open System.Collections.Generic 10 | 11 | module internal Prelude = 12 | let inline flip f x y = f y x 13 | let inline const' k _ = k 14 | let inline choice f g = function Choice2Of2 x -> f x | Choice1Of2 y -> g y 15 | let inline option n f = function None -> n | Some x -> f x 16 | let inline isNull (value : 'T) = match value with null -> true | _ -> false 17 | 18 | [] 19 | module internal Option = 20 | let inline apply f x = 21 | match (f,x) with 22 | | Some f, Some x -> Some (f x) 23 | | _ -> None 24 | 25 | [] 26 | module internal List = 27 | let inline singleton x = [x] 28 | let inline cons x y = x :: y 29 | let inline apply f x = List.collect (fun f -> List.map ((<|) f) x) f 30 | let inline tails x = let rec loop = function [] -> [] | x::xs as s -> s::(loop xs) in loop x 31 | let inline drop i list = 32 | let rec loop i lst = 33 | match (lst, i) with 34 | | ([] as x, _) | (x, 0) -> x 35 | | x, n -> loop (n-1) (List.tail x) 36 | if i > 0 then loop i list else list 37 | 38 | [] 39 | module internal Seq = 40 | let inline bind (f:'a->seq<'b>) x = Seq.collect f x 41 | let inline apply f x = bind (fun f -> Seq.map ((<|) f) x) f 42 | let inline foldBack f x z = Array.foldBack f (Seq.toArray x) z 43 | 44 | let inline chunkBy projection (source : _ seq) = seq { 45 | use e = source.GetEnumerator() 46 | if e.MoveNext() then 47 | let g = ref (projection e.Current) 48 | let members = ref (List()) 49 | (!members).Add(e.Current) 50 | while (e.MoveNext()) do 51 | let key = projection e.Current 52 | if !g = key then (!members).Add(e.Current) 53 | else 54 | yield (!g, !members) 55 | g := key 56 | members := List() 57 | (!members).Add(e.Current) 58 | yield (!g, !members)} 59 | 60 | // http://codebetter.com/matthewpodwysocki/2009/05/06/functionally-implementing-intersperse/ 61 | let inline intersperse sep list = seq { 62 | let notFirst = ref false 63 | for element in list do 64 | if !notFirst then yield sep 65 | yield element 66 | notFirst := true} 67 | 68 | let inline intercalate sep list = seq { 69 | let notFirst = ref false 70 | for element in list do 71 | if !notFirst then yield! sep 72 | yield! element 73 | notFirst := true} 74 | 75 | let inline split options separators source = seq { 76 | match separators |> Seq.map Seq.toList |> Seq.toList with 77 | | [] -> yield source 78 | | separators -> 79 | let buffer = ResizeArray() 80 | let candidate = separators |> List.map List.length |> List.max |> ResizeArray 81 | let mutable i = 0 82 | for item in source do 83 | candidate.Add item 84 | match separators |> List.filter (fun sep -> sep.Length > i && item = sep.[i]) with 85 | | [] -> 86 | i <- 0 87 | buffer.AddRange candidate 88 | candidate.Clear() 89 | | seps -> 90 | match seps |> List.tryFind (fun sep -> sep.Length = i + 1) with 91 | | Some sep -> 92 | i <- 0 93 | if options = System.StringSplitOptions.None || buffer.Count > 0 then yield buffer.ToArray() :> seq<_> 94 | buffer.Clear() 95 | candidate.Clear() 96 | | _ -> i <- i + 1 97 | if candidate.Count > 0 then buffer.AddRange candidate 98 | if options = System.StringSplitOptions.None || buffer.Count > 0 then yield buffer :> seq<_> } 99 | 100 | let inline replace (oldValue:seq<'t>) (newValue:seq<'t>) (source:seq<'t>) :seq<'t> = seq { 101 | let old = oldValue |> Seq.toList 102 | if (old.Length = 0) then 103 | yield! source 104 | else 105 | let candidate = ResizeArray(old.Length) 106 | let mutable sindex = 0 107 | for item in source do 108 | candidate.Add(item) 109 | if (item = old.[sindex]) then 110 | sindex <- sindex + 1 111 | if (sindex >= old.Length) then 112 | sindex <- 0 113 | yield! newValue 114 | candidate.Clear() 115 | else 116 | sindex <- 0 117 | yield! candidate 118 | candidate.Clear() 119 | yield! candidate} 120 | 121 | let inline drop i (source:seq<_>) = 122 | let mutable count = i 123 | use e = source.GetEnumerator() 124 | while (count > 0 && e.MoveNext()) do count <- count-1 125 | seq {while (e.MoveNext()) do yield e.Current} 126 | 127 | [] 128 | module internal Error = 129 | let inline map f = function Choice1Of2 x -> Choice1Of2(f x) | Choice2Of2 x -> Choice2Of2 x 130 | let inline apply f x = 131 | match (f,x) with 132 | | (Choice1Of2 a, Choice1Of2 b) -> Choice1Of2 (a b) 133 | | (Choice2Of2 a, _) -> Choice2Of2 a 134 | | (_, Choice2Of2 b) -> Choice2Of2 b :Choice<'b,'e> 135 | let inline result x = Choice1Of2 x 136 | let inline throw x = Choice2Of2 x 137 | let inline bind (f:'t -> Choice<'v,'e>) = function Choice1Of2 v -> f v | Choice2Of2 e -> Choice2Of2 e 138 | let inline catch (f:'t -> Choice<'v,'e>) = function Choice1Of2 v -> Choice1Of2 v | Choice2Of2 e -> f e 139 | 140 | [] 141 | module internal Implicit = let inline Invoke (x : ^t) = ((^R or ^t) : (static member op_Implicit : ^t -> ^R) x) :^R 142 | 143 | module Errors = 144 | let exnDivByZero = new System.DivideByZeroException() :> exn 145 | let exnNoDivision = new System.Exception "These numbers are not divisible in this domain." 146 | let exnSqrtOfNegative = new System.Exception "Cannot calculate square root of a negative number" 147 | let exnNoSqrt = new System.Exception "No square root defined for this value in this domain." 148 | let exnNoSubtraction = new System.Exception "No subtraction defined for these values in this domain." 149 | 150 | module Decimal = 151 | let inline trySqrt x = 152 | match sign x with 153 | | -1 -> Choice2Of2 Errors.exnSqrtOfNegative 154 | | 0 -> Choice1Of2 0.M 155 | | _ -> 156 | let rec loop previous = 157 | let current = (previous + x / previous) / 2.0M 158 | if previous - current = 0.0M then current else loop current 159 | x |> float |> sqrt |> decimal |> loop |> Choice1Of2 160 | 161 | module Rational = 162 | let inline numerator x = (^F: (member Numerator : 'R) x) 163 | let inline denominator x = (^F: (member Denominator: 'R) x) 164 | 165 | module BigInteger = 166 | open System.Numerics 167 | let trySqrtRem x = 168 | if sign x = -1 then Choice2Of2 Errors.exnSqrtOfNegative 169 | else 170 | let rec loop previous = 171 | let current = (previous + x / previous) >>> 1 172 | if abs (previous - current) < 2I then current else loop current 173 | let guess = 10I ** (((int (BigInteger.Log10 (x + 1I))) + 1) >>> 1) 174 | let r = loop guess 175 | let r2 = r * r 176 | match compare r2 x with 177 | | 0 -> Choice1Of2 (r, 0I) 178 | | 1 -> let root = r - 1I in Choice1Of2 (r, x - r2) 179 | | _ -> Choice1Of2 (r, x - r2) 180 | 181 | 182 | // Dummy types 183 | 184 | type Id<'t>(v:'t) = 185 | let value = v 186 | member this.getValue = value 187 | 188 | [] 189 | module Id = 190 | let run (x:Id<_>) = x.getValue 191 | let map f (x:Id<_>) = Id (f x.getValue) 192 | let create x = Id (x) 193 | 194 | type Id0(v:string) = 195 | let value = v 196 | member this.getValue = value 197 | 198 | type Either<'L,'R> = L of 'L | R of 'R 199 | 200 | type DmStruct = struct end -------------------------------------------------------------------------------- /FsControl.Core/MonadTrans.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open FsControl.Internals 4 | open FsControl.Internals.Prelude 5 | open FsControl.Internals.MonadOps 6 | 7 | // MonadTrans 8 | 9 | type Lift = static member inline Invoke (x:'``Monad<'T>``) = (^``MonadTrans<'Monad<'T>>`` : (static member Lift: _ -> ^``MonadTrans<'Monad<'T>>``) x) 10 | 11 | 12 | // MonadAsync 13 | 14 | type LiftAsync = 15 | static member inline Invoke (x:Async<'T>) :'``MonadAsync<'T>`` = 16 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member LiftAsync: _ -> _) b) 17 | let inline call (a:'a) = fun (x:'x) -> call_2 (a, Unchecked.defaultof<'r>) x :'r 18 | call Unchecked.defaultof x 19 | 20 | static member inline LiftAsync (_:'R ) = fun (x :Async<'T>) -> (^R : (static member LiftAsync: _ -> ^R) x) 21 | static member inline LiftAsync (_:^t when ^t: null and ^t: struct) = () 22 | static member LiftAsync (_:Async<'T> ) = fun (x :Async<'T>) -> x 23 | 24 | 25 | // MonadError 26 | 27 | type Throw = 28 | static member inline Invoke (x:'E) : '``'MonadError<'E,'T>`` = 29 | let inline call_2 (a:^a, b:^R, x) = ((^a or ^R) : (static member Throw: _*_->'R) (b,x)) 30 | let inline call (a:'a, x:'x) = call_2 (a, Unchecked.defaultof<'r>, x) :'r 31 | call (Unchecked.defaultof, x) 32 | 33 | static member inline Throw (_:'R ,x :'E) = (^R : (static member Throw: _ -> ^R) x) 34 | static member inline Throw (_:^t when ^t: null and ^t: struct, _) = id 35 | static member Throw (_:Choice<'T,'E>, x:'E) = Choice2Of2 x: Choice<'T,'E> 36 | 37 | type Catch = 38 | static member Catch (x:Either<'a,'e1>, k:'e1->Either<'a,'e2>) = match x with L v -> L v | R e -> k e 39 | static member Catch (x:Choice<'a,'e1>, k:'e1->Choice<'a,'e2>) = Error.catch k x 40 | 41 | static member inline Invoke (x:'``MonadError<'E1,'T>``) (f:'E1->'``MonadError<'E2,'T>``) : '``MonadError<'E2,'T>`` = 42 | let inline call_3 (a:^a,b:^b,c:^c,f:^f) = ((^a or ^b or ^c) : (static member Catch: _*_ -> _) b, f) 43 | call_3 (Unchecked.defaultof, x, Unchecked.defaultof<'``MonadError<'E2,'T>``>, f) 44 | 45 | 46 | // MonadCont 47 | 48 | type CallCC = static member inline Invoke (f:(('T -> '``MonadCont<'U>``) ->'``MonadCont<'T>``)) = (^``MonadCont<'T>`` : (static member CallCC: _ -> '``MonadCont<'T>``) f) 49 | 50 | 51 | // MonadState 52 | 53 | type Get = static member inline Invoke() : '``MonadState<'S * 'S>`` = (^``MonadState<'S * 'S>`` : (static member Get: _) ()) 54 | type Put = static member inline Invoke (x:'S) : '``MonadState`` = (^``MonadState`` : (static member Put: _ -> _) x) 55 | 56 | 57 | // MonadReader 58 | 59 | type Ask = static member inline Invoke() : '``MonadReader<'R,'T>`` = (^``MonadReader<'R,'T>`` : (static member Ask : _) ()) 60 | type Local = static member inline Invoke (f:'R1->'R2) (m:^``MonadReader<'R2,'T>``) : '``MonadReader<'R1,'T>`` = (^``MonadReader<'R1,'T>`` : (static member Local: _*_ -> _) m, f) 61 | 62 | 63 | // MonadWriter 64 | 65 | type Tell = static member inline Invoke (w:'Monoid) : '``MonadWriter<'Monoid,unit>`` = (^``MonadWriter<'Monoid,unit>`` : (static member Tell : _ -> _) w) 66 | type Listen = static member inline Invoke (m:'``MonadWriter<'Monoid,'T>``) : '``MonadWriter<'Monoid,('T * 'Monoid)>`` = (^``MonadWriter<'Monoid,('T * 'Monoid)>`` : (static member Listen: _ -> _) m) 67 | type Pass = static member inline Invoke (m:'``MonadWriter<'Monoid,('T * ('Monoid -> 'Monoid))>``) : '``MonadWriter<'Monoid,'T>`` = (^``MonadWriter<'Monoid,'T>`` : (static member Pass : _ -> _) m) -------------------------------------------------------------------------------- /FsControl.Core/Monoid.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open System 4 | open System.Text 5 | open System.Collections.Generic 6 | open System.Runtime.CompilerServices 7 | open System.Runtime.InteropServices 8 | open Microsoft.FSharp.Quotations 9 | #if NOTNET35 10 | open System.Threading.Tasks 11 | #endif 12 | open FsControl.Internals 13 | open FsControl.Internals.Prelude 14 | 15 | 16 | type Empty = 17 | inherit Default1 18 | 19 | static member Empty (_:list<'a> , _:Empty) = [] : list<'a> 20 | static member Empty (_:option<'a> , _:Empty) = None :option<'a> 21 | static member Empty (_:array<'a> , _:Empty) = [||] : array<'a> 22 | static member Empty (_:string , _:Empty) = "" 23 | static member Empty (_:StringBuilder, _:Empty) = new StringBuilder() 24 | static member Empty (_:unit , _:Empty) = () 25 | static member Empty (_:Set<'a> , _:Empty) = Set.empty : Set<'a> 26 | static member Empty (_:Map<'a,'b> , _:Empty) = Map.empty : Map<'a,'b> 27 | static member Empty (_:TimeSpan , _:Empty) = TimeSpan() 28 | 29 | static member inline Invoke() = 30 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Empty: _*_ -> _) b, a) 31 | let inline call (a:'a) = call_2 (a, Unchecked.defaultof<'r>) :'r 32 | call Unchecked.defaultof 33 | 34 | type Empty with static member inline Empty (_ : 'a*'b , _:Empty) = (Empty.Invoke(), Empty.Invoke() ): 'a*'b 35 | type Empty with static member inline Empty (_ : 'a*'b*'c , _:Empty) = (Empty.Invoke(), Empty.Invoke(), Empty.Invoke() ): 'a*'b*'c 36 | type Empty with static member inline Empty (_ : 'a*'b*'c*'d , _:Empty) = (Empty.Invoke(), Empty.Invoke(), Empty.Invoke(), Empty.Invoke() ): 'a*'b*'c*'d 37 | type Empty with static member inline Empty (_ : 'a*'b*'c*'d*'e, _:Empty) = (Empty.Invoke(), Empty.Invoke(), Empty.Invoke(), Empty.Invoke(), Empty.Invoke()): 'a*'b*'c*'d*'e 38 | 39 | type Empty with 40 | static member inline Empty (_:'R, _:Default1) = ((^R) : (static member Empty: ^R) ()):'R 41 | 42 | #if NOTNET35 43 | 44 | static member inline Empty (_:Task<'a>, _:Empty) = 45 | let (v:'a) = Empty.Invoke() 46 | let s = TaskCompletionSource() 47 | s.SetResult v 48 | s.Task 49 | #endif 50 | 51 | static member inline Empty (_:'T->'Monoid , _:Empty) = (fun _ -> Empty.Invoke()) :'T->'Monoid 52 | static member inline Empty (_:Async<'a> , _:Empty) = let (v:'a) = Empty.Invoke() in async.Return v 53 | static member inline Empty (_:Expr<'a> , _:Empty) = let (v:'a) = Empty.Invoke() in Expr.Cast<'a>(Expr.Value(v)) 54 | static member inline Empty (_:Lazy<'a> , _:Empty) = let (v:'a) = Empty.Invoke() in lazy v 55 | static member Empty (_:Dictionary<'a,'b>, _:Empty) = Dictionary<'a,'b>() 56 | static member Empty (_:ResizeArray<'a> , _:Empty) = ResizeArray() : ResizeArray<'a> 57 | static member Empty (_:seq<'a> , _:Empty) = Seq.empty : seq<'a> 58 | 59 | 60 | [] 61 | type Append = 62 | []static member Append (x:list<_> , y ) = x @ y 63 | []static member Append (x:array<_> , y ) = Array.append x y 64 | []static member Append (() , ()) = () 65 | []static member Append (x:Set<_> , y ) = Set.union x y 66 | []static member Append (x:string , y ) = x + y 67 | static member Append (x:StringBuilder, y:StringBuilder) = StringBuilder().Append(x).Append(y) 68 | []static member Append (x:TimeSpan , y:TimeSpan) = x + y 69 | 70 | static member inline Invoke (x:'T) (y:'T) :'T = 71 | let inline call_3 (m:^M, a:^t, b:^t) = ((^M or ^t) : (static member Append: _*_ -> _) a, b) 72 | call_3 (Unchecked.defaultof, x, y) 73 | 74 | type Append with 75 | []static member inline Append (x:option<_>,y ) = 76 | match (x,y) with 77 | | (Some a , Some b) -> Some (Append.Invoke a b) 78 | | (Some a , None ) -> Some a 79 | | (None , Some b) -> Some b 80 | | _ -> None 81 | 82 | 83 | type Append with 84 | []static member inline Append ((x1,x2 ), (y1,y2 )) = (Append.Invoke x1 y1, Append.Invoke x2 y2 ) :'a*'b 85 | type Append with 86 | []static member inline Append ((x1,x2,x3 ), (y1,y2,y3 )) = (Append.Invoke x1 y1, Append.Invoke x2 y2, Append.Invoke x3 y3 ) :'a*'b*'c 87 | type Append with 88 | []static member inline Append ((x1,x2,x3,x4 ), (y1,y2,y3,y4 )) = (Append.Invoke x1 y1, Append.Invoke x2 y2, Append.Invoke x3 y3, Append.Invoke x4 y4 ) :'a*'b*'c*'d 89 | type Append with 90 | []static member inline Append ((x1,x2,x3,x4,x5), (y1,y2,y3,y4,y5)) = (Append.Invoke x1 y1, Append.Invoke x2 y2, Append.Invoke x3 y3, Append.Invoke x4 y4, Append.Invoke x5 y5) :'a*'b*'c*'d*'e 91 | 92 | type Append with 93 | 94 | #if NOTNET35 95 | []static member inline Append (x:'a Task, y:'a Task) = 96 | x.ContinueWith(fun (t: Task<_>) -> 97 | (fun a -> 98 | y.ContinueWith(fun (u: Task<_>) -> 99 | Append.Invoke a u.Result)) t.Result).Unwrap() 100 | #endif 101 | 102 | []static member inline Append (x:Map<'a,'b>, y) = 103 | Map.fold (fun m k v' -> Map.add k (match Map.tryFind k m with Some v -> Append.Invoke v v' | None -> v') m) x y 104 | 105 | []static member inline Append (x:Dictionary<'Key,'Value>, y:Dictionary<'Key,'Value>) = 106 | let d = Dictionary<'Key,'Value>() 107 | for KeyValue(k, v ) in x do d.[k] <- v 108 | for KeyValue(k, v') in y do d.[k] <- match d.TryGetValue k with true, v -> Append.Invoke v v' | _ -> v' 109 | d 110 | 111 | []static member inline Append (f:'T->'Monoid, g:'T->'Monoid) = (fun x -> Append.Invoke (f x) (g x)) :'T->'Monoid 112 | 113 | []static member inline Append (x:'S Async, y:'S Async) = async { 114 | let! a = x 115 | let! b = y 116 | return Append.Invoke a b} 117 | 118 | []static member inline Append (x:'a Expr, y:'a Expr) :'a Expr = 119 | let inline f (x:'a) :'a -> 'a = Append.Invoke x 120 | Expr.Cast<'a>(Expr.Application(Expr.Application(Expr.Value(f), x), y)) 121 | 122 | 123 | []static member inline Append (x:'a Lazy , y:'a Lazy) = lazy Append.Invoke (x.Value) (y.Value) 124 | []static member Append (x:_ ResizeArray, y:_ ResizeArray) = ResizeArray (Seq.append x y) 125 | []static member Append (x:_ IObservable, y ) = Observable.merge x y 126 | []static member Append (x:_ seq , y ) = Seq.append x y 127 | 128 | 129 | [] 130 | type Concat = 131 | inherit Default1 132 | []static member inline Concat (x:seq>, []output:Dictionary<'a,'b>, []impl:Concat) = 133 | let dct = Dictionary<'a,'b>() 134 | for d in x do 135 | for KeyValue(k, u) in d do 136 | dct.[k] <- match dct.TryGetValue k with true, v -> Append.Invoke v u | _ -> u 137 | dct 138 | 139 | []static member inline Concat (x:seq>, []output:'a ResizeArray, []impl:Concat) = ResizeArray (Seq.concat x) 140 | []static member Concat (x:seq> , []output:list<'a> , []impl:Concat) = List.concat x 141 | []static member Concat (x:seq> , []output:array<'a> , []impl:Concat) = Array.concat x 142 | []static member Concat (x:seq , []output:string , []impl:Concat) = String.Concat x 143 | []static member Concat (x:seq , []output:StringBuilder , []impl:Concat) = (StringBuilder(), x) ||> Seq.fold (fun x -> x.Append) 144 | 145 | static member inline Invoke (x:seq<'T>) : 'T = 146 | let inline call_3 (a:^a, b:^b, c:^c) = ((^a or ^b or ^c) : (static member Concat: _*_*_ -> _) b, c, a) 147 | let inline call (a:'a, b:'b) = call_3 (a, b, Unchecked.defaultof<'r>) :'r 148 | call (Unchecked.defaultof, x) 149 | 150 | type Concat with 151 | []static member inline Concat (x:seq<'a * 'b>, []output:'a * 'b, []impl:Concat) = 152 | Concat.Invoke (Seq.map fst x), 153 | Concat.Invoke (Seq.map snd x) 154 | 155 | type Concat with 156 | []static member inline Concat (x:seq<'a * 'b * 'c>, []output:'a * 'b * 'c, []impl:Concat) = 157 | Concat.Invoke (Seq.map (fun (x,_,_) -> x) x), 158 | Concat.Invoke (Seq.map (fun (_,x,_) -> x) x), 159 | Concat.Invoke (Seq.map (fun (_,_,x) -> x) x) 160 | 161 | type Concat with 162 | []static member inline Concat (x:seq<'a * 'b * 'c * 'd>, []output:'a * 'b * 'c * 'd, []impl:Concat) = 163 | Concat.Invoke (Seq.map (fun (x,_,_,_) -> x) x), 164 | Concat.Invoke (Seq.map (fun (_,x,_,_) -> x) x), 165 | Concat.Invoke (Seq.map (fun (_,_,x,_) -> x) x), 166 | Concat.Invoke (Seq.map (fun (_,_,_,x) -> x) x) 167 | 168 | type Concat with 169 | []static member inline Concat (x:seq< 'a>, []output:'a, _:Default2) = Seq.fold Append.Invoke (Empty.Invoke()) x:'a 170 | 171 | type Concat with 172 | []static member inline Concat (x:seq< ^R>, []output:^R, _:Default1) = ((^R) : (static member Concat: 'R seq -> ^R) x) 173 | static member inline Concat (x:seq< ^R>, _:^t when ^t: null and ^t: struct, _:Default1) = fun () -> id 174 | -------------------------------------------------------------------------------- /FsControl.Core/Operators.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open FsControl 4 | 5 | module Operators = 6 | 7 | // Functor ---------------------------------------------------------------- 8 | 9 | /// Lift a function into a Functor. 10 | let inline map (f:'T->'U) (x:'``Functor<'T>``) :'``Functor<'U>`` = Map.Invoke f x 11 | 12 | /// Lift a function into a Functor. Same as map. 13 | let inline () (f:'T->'U) (x:'``Functor<'T>``) :'``Functor<'U>`` = Map.Invoke f x 14 | 15 | /// Lift a function into a Functor. Same as map. 16 | let inline (<<|) (f:'T->'U) (x:'``Functor<'T>``) :'``Functor<'U>`` = Map.Invoke f x 17 | 18 | /// Lift a function into a Functor. Same as map but with flipped arguments. 19 | let inline (|>>) (x:'``Functor<'T>``) (f:'T->'U) :'``Functor<'U>`` = Map.Invoke f x 20 | 21 | /// Like map but ignoring the results. 22 | let inline iter (action :'T->unit) (source :'``Functor<'T>``) :unit = Iterate.Invoke action source 23 | 24 | 25 | // Applicative ------------------------------------------------------------ 26 | 27 | /// Lift a value into a Functor. Same as return in Computation Expressions. 28 | let inline result (x:'T): '``Functor<'T>`` = Return.Invoke x 29 | 30 | /// Apply a lifted argument to a lifted function. 31 | let inline (<*>) (x:'``Applicative<'T -> 'U>``) (y:'``Applicative<'T>``): '``Applicative<'U>`` = Apply.Invoke x y : '``Applicative<'U>`` 32 | 33 | /// Apply 2 lifted arguments to a lifted function. 34 | let inline liftA2 (f:'T->'U->'V) (a:'``Applicative<'T>``) (b:'``Applicative<'U>``) : '``Applicative<'V>`` = f a <*> b 35 | 36 | let inline ( *>) (x:'``Applicative<'T>``) : '``Applicative<'U>``->'``Applicative<'U>`` = x |> liftA2 (fun _ -> id) 37 | let inline (<* ) (x:'``Applicative<'T>``) : '``Applicative<'U>``->'``Applicative<'T>`` = x |> liftA2 (fun k _ -> k ) 38 | let inline (<**>) (x:'``Applicative<'T>``) : '``Applicative<'T -> 'U>``->'``Applicative<'U>`` = x |> liftA2 (|>) 39 | let inline optional (v:'``Applicative<'T>``) : '``Applicative`` = Some v <|> result None 40 | 41 | 42 | // Monad ----------------------------------------------------------- 43 | 44 | /// Takes a monadic value and a function from a plain type to a monadic value, and returns a new monadic value. 45 | let inline (>>=) (x:'``Monad<'T>``) (f:'T->'``Monad<'U>``) :'``Monad<'U>`` = Bind.Invoke x f 46 | 47 | /// Takes a function from a plain type to a monadic value and a monadic value, and returns a new monadic value. 48 | let inline (=<<) (f:'T->'``Monad<'U>``) (x:'``Monad<'T>``) :'``Monad<'U>`` = Bind.Invoke x f 49 | 50 | let inline (>=>) (f:'T->'``Monad<'U>``) (g:'U->'``Monad<'V>``) (x:'T) : '``Monad<'V>`` = Bind.Invoke (f x) g 51 | let inline (<=<) (g:'b->'``Monad<'V>``) (f:'T->'``Monad<'U>``) (x:'T) : '``Monad<'V>`` = Bind.Invoke (f x) g 52 | 53 | /// Flattens two layers of monadic information into one. 54 | let inline join (x:'``Monad>``) : '``Monad<'T>`` = Join.Invoke x 55 | 56 | 57 | // Monoid ----------------------------------------------------------------- 58 | 59 | let inline getEmpty() :'Monoid = Empty.Invoke() 60 | let inline (++) (x:'Monoid) (y:'Monoid): 'Monoid = Append.Invoke x y 61 | let inline append (x:'Monoid) (y:'Monoid): 'Monoid = Append.Invoke x y 62 | let inline concat (x:seq<'Monoid>) : 'Monoid = Concat.Invoke x 63 | 64 | 65 | // Alternative/Monadplus/Arrowplus ---------------------------------------- 66 | 67 | let inline getMZero() :'``Functor<'T>`` = MZero.Invoke() 68 | let inline (<|>) (x:'``Functor<'T>``) (y:'``Functor<'T>``) : '``Functor<'T>`` = MPlus.Invoke x y 69 | let inline guard x: '``MonadPlus`` = if x then Return.Invoke () else MZero.Invoke() 70 | 71 | 72 | // Contravariant/Bifunctor/Profunctor ------------------------------------- 73 | 74 | let inline contramap (f : 'U->'T) (x:'``Contravariant<'T>``) : '``Contravariant<'U>`` = Contramap.Invoke f x 75 | let inline bimap (f : 'T->'U) (g : 'V->'W) (source : '``Bifunctor<'T,'V>``) : '``Bifunctor<'U,'W>`` = Bimap.Invoke f g source 76 | let inline first (f : 'T->'V) (source : '``Bifunctor<'T,'V>``) : '``Bifunctor<'U,'V>`` = MapFirst.Invoke f source 77 | let inline second (f : 'V->'W) (source : '``Bifunctor<'T,'V>``) : '``Bifunctor<'T,'W>`` = MapSecond.Invoke f source 78 | let inline dimap (f : 'A->'B) ( g: 'C->'D) (source : '``Profunctor<'B,'C>``) : '``Profunctor<'A,'D>`` = Dimap.Invoke f g source 79 | let inline lmap (f : 'A->'B) (source : ^``Profunctor<'B,'C>``) : '``Profunctor<'A,'C>`` = LMap.Invoke f source 80 | let inline rmap (f : 'C->'D) (source : '``Profunctor<'B,'C>``) : '``Profunctor<'B,'D>`` = RMap.Invoke f source 81 | 82 | 83 | // Category --------------------------------------------------------------- 84 | 85 | /// the identity morphism. 86 | let inline getCatId() = Id.Invoke() : '``Category<'T,'T>`` 87 | 88 | /// Right-to-left morphism composition. 89 | let inline catComp (f : '``Category<'U,'V>``) (g : '``Category<'T,'U>``) : '``Category<'T,'V>`` = Comp.Invoke f g 90 | 91 | 92 | // Arrow ------------------------------------------------------------------ 93 | 94 | /// Lift a function to an arrow. 95 | let inline arr (f : 'T -> 'U) : '``Arrow<'T,'U>`` = Arr.Invoke f 96 | 97 | /// Send the first component of the input through the argument arrow, and copy the rest unchanged to the output. 98 | let inline arrFirst (f : '``Arrow<'T,'U>``) : '``Arrow<('T * 'V),('U * 'V)>`` = ArrFirst.Invoke f 99 | 100 | /// Send the second component of the input through the argument arrow, and copy the rest unchanged to the output. 101 | let inline arrSecond (f : '``Arrow<'T,'U>``) : '``Arrow<('V * 'T),('V * 'U)>`` = ArrSecond.Invoke f 102 | 103 | /// Split the input between the two argument arrows and combine their output. Note that this is in general not a functor. 104 | let inline ( ***) (f : '``Arrow<'T1,'U1>``) (g : '``Arrow<'T2,'U2>``) : '``Arrow<('T1 * 'T2),('U1 * 'U2)>`` = ArrCombine.Invoke f g 105 | 106 | /// Send the input to both argument arrows and combine their output. Also known as the (&&&) operator. 107 | let inline fanout (f : '``Arrow<'T,'U1>``) (g : '``Arrow<'T,'U2>``) : '``Arrow<'T,('U1 * 'U2)>`` = Fanout.Invoke f g 108 | 109 | 110 | // Arrow Choice------------------------------------------------------------ 111 | 112 | /// Split the input between the two argument arrows and merge their outputs. Also known as the (|||) operator. 113 | let inline fanin (f : '``ArrowChoice<'T,'V>``) (g : '``ArrowChoice<'U,'V>``) : '``ArrowChoice,'V>`` = Fanin.Invoke f g 114 | 115 | /// Split the input between both argument arrows, retagging and merging their outputs. Note that this is in general not a functor. 116 | let inline (+++) (f : '``ArrowChoice<'T1,'U1>``) (g : '``ArrowChoice<'T2,'U2>``) : '``ArrowChoice,Choice<'U2,'U1>>`` = AcMerge.Invoke f g 117 | 118 | /// Feed marked inputs through the left argument arrow, passing the rest through unchanged to the output. 119 | let inline left (f : '``ArrowChoice<'T,'U>``) : '``ArrowChoice,Choice<'V,'U>>`` = AcLeft.Invoke f 120 | 121 | /// Feed marked inputs through the right argument arrow, passing the rest through unchanged to the output. 122 | let inline right (f : '``ArrowChoice<'T,'U>``) : '``ArrowChoice,Choice<'U,'V>>`` = AcRight.Invoke f 123 | 124 | 125 | // Arrow Apply ------------------------------------------------------------ 126 | 127 | /// Apply an arrow produced as the output of some previous computation to an input, producing its output as the output of app. 128 | let inline getApp() = App.Invoke() : '``ArrowApply<('ArrowApply<'T,'U> * 'T)>,'U)>`` 129 | 130 | 131 | // Foldable 132 | 133 | let inline ofList (source :list<'T>) = OfList.Invoke source 134 | let inline ofSeq (source :seq<'T> ) = OfSeq.Invoke source 135 | let inline foldBack (folder:'T->'State->'State) (foldable:'``Foldable<'T>``) (state:'State) : 'State = FoldBack.Invoke folder state foldable 136 | let inline fold (folder:'State->'T->'State) (state:'State) (foldable:'``Foldable<'T>``) : 'State = Fold.Invoke folder state foldable 137 | let inline foldMap (f:'T->'Monoid) (x:'``Foldable<'T>``) : 'Monoid = FoldMap.Invoke f x 138 | let inline toList value :'T list = ToList.Invoke value 139 | let inline toArray value :'T [] = ToArray.Invoke value 140 | let inline exists (predicate :'T->bool) (source:'``Foldable<'T>``) = Exists.Invoke predicate source :bool 141 | let inline forall (predicate :'T->bool) (source:'``Foldable<'T>``) = ForAll.Invoke predicate source :bool 142 | let inline find (predicate :'T->bool) (source:'``Foldable<'T>``) = Find.Invoke predicate source :'T 143 | let inline tryFind (predicate :'T->bool) (source:'``Foldable<'T>``) = TryFind.Invoke predicate source :'T option 144 | let inline pick (chooser:'T->'U option) (source:'``Foldable<'T>``) = Pick.Invoke chooser source :'U 145 | let inline tryPick (chooser:'T->'U option) (source:'``Foldable<'T>``) = TryPick.Invoke chooser source :'U option 146 | let inline filter (predicate:_->bool) (x:'``Foldable<'a>``) :'``Foldable<'a>`` = Filter.Invoke predicate x 147 | let inline intercalate (sep:'Monoid) (source:'``Foldable<'Monoid>``) = Intercalate.Invoke sep source : 'Monoid 148 | let inline intersperse (sep:'T) (source:'``Foldable<'T>``) = Intersperse.Invoke sep source : '``Foldable<'T>`` 149 | 150 | 151 | // Traversable 152 | 153 | /// Map each element of a structure to an action, evaluate these actions from left to right, and collect the results. 154 | let inline traverse (f:'T->'``Applicative<'U>``) (t:'``Traversable<'T>>``) : '``Applicative<'Traversable<'U>>`` = Traverse.Invoke f t 155 | 156 | /// Evaluate each action in the structure from left to right, and and collect the results. 157 | let inline sequenceA (t:'``Traversable<'Applicative<'T>>``) :'``Applicative<'Traversable<'T>>`` = SequenceA.Invoke t 158 | 159 | 160 | // Indexable 161 | 162 | /// Get an item from the given index. 163 | let inline item (n:'K) (source:'``Indexed<'T>``) : 'T = Item.Invoke n source 164 | 165 | /// Map with access to the index. 166 | let inline mapi (mapping:'K->'T->'U) (source:'``FunctorWithIndex<'T>``) : '``FunctorWithIndex<'U>`` = MapIndexed.Invoke mapping source 167 | 168 | /// Map an action with access to an index. 169 | let inline iteri (action:'K->'T->unit) (source:'``FunctorWithIndex<'T>``) : unit = IterateIndexed.Invoke action source 170 | 171 | /// Left-associative fold of an indexed container with access to the index i. 172 | let inline foldi (folder:'State->'K->'T->'State) (state:'State) (source:'``FoldableWithIndex<'T>``) : 'State = FoldIndexed.Invoke folder state source 173 | 174 | /// Traverse an indexed container. Behaves exactly like a regular traverse except that the traversing function also has access to the key associated with a value. 175 | let inline traversei (f:'K->'T->'``Applicative<'U>``) (t:'``Traversable<'T>>``) : '``Applicative<'Traversable<'U>>`` = TraverseIndexed.Invoke f t 176 | 177 | 178 | // Comonads 179 | 180 | let inline extract (x:'``Comonad<'T>``): 'T = Extract.Invoke x 181 | let inline extend (g:'``Comonad<'T>``->'U) (s:'``Comonad<'T>``): '``Comonad<'U>`` = Extend.Invoke g s 182 | let inline (=>>) (s:'``Comonad<'T>``) (g:'``Comonad<'T>``->'U): '``Comonad<'U>`` = Extend.Invoke g s 183 | let inline duplicate (x : '``Comonad<'T>``) : '``Comonad<'Comonad<'T>>`` = Duplicate.Invoke x 184 | 185 | 186 | // Monad Transformers 187 | 188 | /// Lift a computation from the inner monad to the constructed monad. 189 | let inline lift (x:'``Monad<'T>``) : '``MonadTrans<'Monad<'T>>`` = Lift.Invoke x 190 | 191 | /// A lift specializaed for Async<'T> which is able to bring an Async value from any depth of monad-layers. 192 | let inline liftAsync (x:Async<'T>) : '``MonadAsync<'T>`` = LiftAsync.Invoke x 193 | 194 | /// (call-with-current-continuation) calls a function with the current continuation as its argument. 195 | let inline callCC (f:('T->'``MonadCont<'R,'U>``)->'``MonadCont<'R,'T>``) : '``MonadCont<'R,'T>`` = CallCC.Invoke f 196 | 197 | /// Return the state from the internals of the monad. 198 | let inline get< ^``MonadState<'S * 'S>`` when ^``MonadState<'S * 'S>`` : (static member Get : ^``MonadState<'S * 'S>``)> = (^``MonadState<'S * 'S>`` : (static member Get : _) ()) 199 | 200 | /// Replace the state inside the monad. 201 | let inline put (x:'S) : '``MonadState`` = Put.Invoke x 202 | 203 | /// Retrieves the monad environment. 204 | let inline ask< ^``MonadReader<'R,'T>`` when ^``MonadReader<'R,'T>`` : (static member Ask : ^``MonadReader<'R,'T>``)> = (^``MonadReader<'R,'T>`` : (static member Ask : _) ()) 205 | 206 | /// Executes a computation in a modified environment. 207 | /// The function to modify the environment. 208 | /// Reader to run in the modified environment. 209 | let inline local (f:'R1->'R2) (m:'``MonadReader<'R2,'T>``) : '``MonadReader<'R1,'T>`` = Local.Invoke f m 210 | 211 | /// Embeds a simple writer action. 212 | let inline tell (w:'Monoid) : '``MonadWriter<'Monoid,unit>`` = Tell.Invoke w 213 | 214 | /// An action that executes the action and adds its output to the value of the computation. 215 | /// The action to be executed. 216 | let inline listen (m:'``MonadWriter<'Monoid,'T>``) : '``MonadWriter<'Monoid,('T * 'Monoid)>`` = Listen.Invoke m 217 | 218 | /// Action that executes the action m, which returns a value and a function, and returns the value, applying the function to the output. 219 | let inline pass (m:'``MonadWriter<'Monoid,('T * ('Monoid -> 'Monoid))>``) : '``MonadWriter<'Monoid,'T>`` = Pass.Invoke m 220 | 221 | /// Throws an error value inside the Error monad. 222 | let inline throw (error:'E) : '``'MonadError<'E,'T>`` = Throw.Invoke error 223 | 224 | /// Executes a handler when the value contained in the Error monad represents an error. 225 | let inline catch (value:'``'MonadError<'E1,'T>``) (handler:'E1->'``'MonadError<'E2,'T>``) : '``'MonadError<'E2,'T>`` = Catch.Invoke value handler 226 | 227 | 228 | // Collection 229 | 230 | let inline nth (n:int) (source:'``Collection<'T>``) : 'T = Nth.Invoke n source 231 | 232 | /// Returns a collection that skips N elements of the original collection and then yields the 233 | /// remaining elements of the collection. 234 | /// Throws InvalidOperationException 235 | /// when count exceeds the number of elements in the collection. drop 236 | /// returns an empty collection instead of throwing an exception. 237 | /// The number of items to skip. 238 | /// The input collection. 239 | /// 240 | /// The result collection. 241 | /// 242 | /// Thrown when the input collection is null. 243 | /// Thrown when count exceeds the number of elements 244 | /// in the collection. 245 | let inline skip (count:int) (source:'``Collection<'T>``) : '``Collection<'T>`` = Skip.Invoke count source 246 | 247 | /// Returns the first N elements of the collection. 248 | /// Throws InvalidOperationException 249 | /// if the count exceeds the number of elements in the collection. limit 250 | /// returns as many items as the collection contains instead of throwing an exception. 251 | /// 252 | /// The number of items to take. 253 | /// The input collection. 254 | /// 255 | /// The result collection. 256 | /// 257 | /// Thrown when the input collection is null. 258 | /// Thrown when the input collection is empty. 259 | /// Thrown when count exceeds the number of elements 260 | /// in the collection. 261 | let inline take (count:int) (source:'``Collection<'T>``) : '``Collection<'T>`` = Take.Invoke count source 262 | 263 | /// Returns a collection that drops N elements of the original collection and then yields the 264 | /// remaining elements of the collection. 265 | /// The number of items to drop. 266 | /// The input collection. 267 | /// 268 | /// The result collection. 269 | let inline drop (count:int) (source:'``Collection<'T>``) : '``Collection<'T>`` = Drop.Invoke count source 270 | 271 | /// Returns a collection with at most N elements. 272 | /// 273 | /// The maximum number of items to return. 274 | /// The input collection. 275 | /// 276 | /// The result collection. 277 | /// 278 | /// Thrown when the input sequence is null. 279 | let inline limit (count:int) (source:'``Collection<'T>``) : '``Collection<'T>`` = Limit.Invoke count source 280 | 281 | /// Applies a key-generating function to each element of a collection and yields a collection of 282 | /// unique keys. Each unique key contains a collection of all elements that match 283 | /// to this key. 284 | /// 285 | /// This function returns a collection that digests the whole initial collection as soon as 286 | /// that collection is iterated. As a result this function should not be used with 287 | /// large or infinite collections. The function makes no assumption on the ordering of the original 288 | /// collection. 289 | /// 290 | /// A function that transforms an element of the collection into a comparable key. 291 | /// The input collection. 292 | /// 293 | /// The result collection. 294 | let inline groupBy (projection:'T->'Key) (source:'``Collection<'T>``) : '``Collection<'Key * 'Collection<'T>>`` = GroupBy.Invoke projection source 295 | 296 | /// Applies a key-generating function to each element of a collection and yields a collection of 297 | /// keys. Each key contains a collection of all adjacent elements that match 298 | /// to this key. 299 | /// 300 | /// The function makes no assumption on the ordering of the original 301 | /// collection. 302 | /// 303 | /// A function that transforms an element of the collection into a comparable key. 304 | /// The input collection. 305 | /// 306 | /// The result collection. 307 | let inline chunkBy (projection:'T->'Key) (source:'``Collection<'T>``) : '``Collection<'Key * 'Collection<'T>>`` = ChunkBy.Invoke projection source 308 | 309 | 310 | let inline choose (chooser:'T->'U option) (source:'``Collection<'T>``) : '``Collection<'U>`` = Choose.Invoke chooser source 311 | 312 | let inline distinct (source:'``Collection<'T>``) : '``Collection<'T>`` = Distinct.Invoke source 313 | let inline distinctBy (projection:'T->'Key) (source:'``Collection<'T>``) : '``Collection<'T>`` = DistinctBy.Invoke projection source 314 | 315 | let inline head (source:'``Collection<'T>``) = Head.Invoke source :'T 316 | let inline tryHead (source:'``Collection<'T>``) = TryHead.Invoke source :'T option 317 | 318 | let inline length (source:'``Collection<'T>``) :int = Length.Invoke source 319 | 320 | let inline maxBy (projection:'T->'U) (source:'``Collection<'T>``) = MaxBy.Invoke projection source : 'T 321 | let inline minBy (projection:'T->'U) (source:'``Collection<'T>``) = MinBy.Invoke projection source : 'T 322 | 323 | let inline replace (oldValue:'Collection) (newValue:'Collection) (source:'Collection) = Replace.Invoke oldValue newValue source : 'Collection 324 | let inline rev (source:'``Collection<'T>``) = Rev.Invoke source :'``Collection<'T>`` 325 | let inline scan (folder:'State'->'T->'State) state (source:'``Collection<'T>``) = Scan.Invoke folder (state:'State) source : '``Collection<'State>`` 326 | 327 | let inline sort (source:'``Collection<'T>``) : '``Collection<'T>`` = Sort.Invoke source 328 | let inline sortBy (projection:'T->'Key) (source:'``Collection<'T>``) : '``Collection<'T>`` = SortBy.Invoke projection source 329 | let inline split (sep:seq<'Collection>) (source:'Collection) = Split.Invoke sep source : seq<'Collection> 330 | let inline toSeq (source:'``Collection<'T>``) = ToSeq.Invoke source :seq<'T> 331 | 332 | let inline unzip (source: '``Collection<'T1 * 'T2>``) = Unzip.Invoke source : '``Collection<'T1>`` * '``Collection<'T2>`` 333 | let inline zip (source1:'``Collection<'T1>``) (source2:'``Collection<'T2>``) : '``Collection<'T1 * 'T2>`` = Zip.Invoke source1 source2 334 | 335 | 336 | 337 | 338 | // Tuple 339 | 340 | /// Gets the value of the first component of a tuple. 341 | let inline item1 tuple = Item1.Invoke tuple 342 | 343 | /// Gets the value of the second component of a tuple. 344 | let inline item2 tuple = Item2.Invoke tuple 345 | 346 | /// Gets the value of the third component of a tuple. 347 | let inline item3 tuple = Item3.Invoke tuple 348 | 349 | /// Gets the value of the fourth component of a tuple. 350 | let inline item4 tuple = Item4.Invoke tuple 351 | 352 | /// Gets the value of the fifth component of a tuple. 353 | let inline item5 tuple = Item5.Invoke tuple 354 | 355 | let inline mapItem1 mapping tuple = MapItem1.Invoke mapping tuple 356 | let inline mapItem2 mapping tuple = MapItem2.Invoke mapping tuple 357 | let inline mapItem3 mapping tuple = MapItem3.Invoke mapping tuple 358 | let inline mapItem4 mapping tuple = MapItem4.Invoke mapping tuple 359 | let mapItem5 mapping tuple = MapItem5.MapItem5(tuple, mapping) 360 | 361 | 362 | 363 | // Converter 364 | 365 | /// Convert using the explicit operator. 366 | let inline explicit (value:'T) :'U = Explicit.Invoke value 367 | 368 | let inline ofBytesWithOptions (isLtEndian:bool) (startIndex:int) (value:byte[]) = OfBytes.Invoke isLtEndian startIndex value 369 | let inline ofBytes (value:byte[]) = OfBytes.Invoke true 0 value 370 | let inline ofBytesBE (value:byte[]) = OfBytes.Invoke false 0 value 371 | 372 | let inline toBytes value :byte[] = ToBytes.Invoke true value 373 | let inline toBytesBE value :byte[] = ToBytes.Invoke false value 374 | 375 | let inline toStringWithCulture (cultureInfo:System.Globalization.CultureInfo) value:string = ToString.Invoke cultureInfo value 376 | let inline toString value:string = ToString.Invoke System.Globalization.CultureInfo.InvariantCulture value 377 | 378 | /// Converts to a value from its string representation. 379 | let inline parse (value:string) = Parse.Invoke value 380 | 381 | /// Converts to a value from its string representation. Returns None if the convertion doesn't succeed. 382 | let inline tryParse (value:string) = TryParse.Invoke value 383 | 384 | 385 | // Numerics 386 | 387 | /// Gets a value that represents the number 0 (zero). 388 | let inline getZero() = Zero.Invoke() 389 | 390 | /// Gets a value that represents the number 1 (one). 391 | let inline getOne() = One.Invoke() 392 | 393 | /// Divides one number by another, returns a tuple with the result and the remainder. 394 | let inline divRem (D:'T) (d:'T) :'T*'T = DivRem.Invoke D d 395 | 396 | /// Returns the smallest possible value. 397 | let inline minValue() = MinValue.Invoke() 398 | 399 | /// Returns the largest possible value. 400 | let inline maxValue() = MaxValue.Invoke() 401 | 402 | /// Converts from BigInteger to the inferred destination type. 403 | let inline fromBigInt (x:bigint) :'Num = FromBigInt.Invoke x 404 | 405 | /// Converts to BigInteger. 406 | let inline toBigInt (x:'Integral) :bigint = ToBigInt.Invoke x 407 | 408 | /// Gets the pi number. 409 | let inline getPi() :'Floating = Pi.Invoke() 410 | 411 | /// Returns the additive inverse of the number. 412 | let inline negate (x:'Num): 'Num = x |> TryNegate.Invoke |> function Choice1Of2 x -> x | Choice2Of2 e -> raise e 413 | 414 | /// Returns the additive inverse of the number. 415 | /// Works also for unsigned types (Throws an exception if there is no inverse). 416 | let inline negate' (x:'Num): 'Num = x |> TryNegate'.Invoke |> function Choice1Of2 x -> x | Choice2Of2 e -> raise e 417 | 418 | /// Returns the additive inverse of the number. 419 | /// Works also for unsigned types (Returns none if there is no inverse). 420 | let inline tryNegate' (x:'Num): 'Num option = TryNegate'.Invoke x |> function Choice1Of2 x -> Some x | Choice2Of2 e -> None 421 | 422 | /// Returns the subtraction between two numbers. Throws an error if the result is negative on unsigned types. 423 | let inline subtract (x:'Num) (y:'Num): 'Num = Subtract.Invoke x y 424 | 425 | /// Returns the subtraction between two numbers. Returns None if the result is negative on unsigned types. 426 | let inline trySubtract (x:'Num) (y:'Num): 'Num option = y |> TrySubtract.Invoke x |> function Choice1Of2 x -> Some x | Choice2Of2 e -> None 427 | 428 | /// Returns the division between two numbers. If the numbers are not divisible throws an error. 429 | let inline div (dividend:'Num) (divisor:'Num): 'Num = Divide.Invoke dividend divisor 430 | 431 | /// Returns the division between two numbers. Returns None if the numbers are not divisible. 432 | let inline tryDiv (dividend:'Num) (divisor:'Num): 'Num option = divisor |> TryDivide.Invoke dividend |> function Choice1Of2 x -> Some x | Choice2Of2 e -> None 433 | 434 | /// Returns the square root of a number of any type. Throws an exception if there is no square root. 435 | let inline sqrt x = x |> Sqrt.Invoke 436 | 437 | /// Returns the square root of a number of any type. Returns None if there is no square root. 438 | let inline trySqrt x = x |> TrySqrt.Invoke |> function Choice1Of2 x -> Some x | Choice2Of2 _ -> None 439 | 440 | /// Returns the square root of an integral number. 441 | let inline isqrt (x:'Integral): 'Integral = x |> TrySqrtRem.Invoke |> function Choice1Of2 (x, _) -> x | Choice2Of2 e -> raise e 442 | 443 | /// Returns the square root of an integral number. 444 | let inline sqrtRem (x:'Integral): 'Integral*'Integral = x |> TrySqrtRem.Invoke |> function Choice1Of2 x -> x | Choice2Of2 e -> raise e 445 | 446 | /// Returns a number which represents the sign. 447 | /// Rule: signum x * abs x = x 448 | let inline signum (x:'Num): 'Num = Signum.Invoke x 449 | 450 | /// Returns a number which represents the sign. 451 | /// Works also for unsigned types. 452 | /// Rule: signum x * abs x = x 453 | let inline signum' (x:'Num): 'Num = Signum'.Invoke x 454 | 455 | /// Gets the absolute value of a number. 456 | /// Rule: signum x * abs x = x 457 | let inline abs (x:'Num): 'Num = Abs.Invoke x 458 | 459 | /// Gets the absolute value of a number. 460 | /// Works also for unsigned types. 461 | /// Rule: signum x * abs x = x 462 | let inline abs' (x:'Num): 'Num = Abs'.Invoke x 463 | -------------------------------------------------------------------------------- /FsControl.Core/Samples/Collections.fsx: -------------------------------------------------------------------------------- 1 | #nowarn "3186" 2 | #r @"..\bin\Release\FsControl.dll" 3 | 4 | open System 5 | open FsControl 6 | open FsControl.Operators 7 | 8 | let flip f x y = f y x 9 | let konst k _ = k 10 | let () 11 | let (/>) = flip 12 | 13 | type Endo<'T> = Endo of ('T -> 'T) with 14 | static member get_Empty() = Endo id 15 | static member Append (Endo f, Endo g) = Endo (f << g) 16 | 17 | module Endo = let run (Endo x) = x 18 | 19 | type Tree<'a> = 20 | | Empty 21 | | Leaf of 'a 22 | | Node of (Tree<'a>) * 'a * (Tree<'a>) 23 | 24 | // add instance for Foldable abstraction (ToSeq is the minimal definition). 25 | static member ToSeq x = 26 | let rec loop t = seq { 27 | match t with 28 | | Empty -> () 29 | | Leaf n -> yield n 30 | | Node (l,k,r) -> yield k; yield! loop l; yield! loop r} 31 | loop x 32 | 33 | static member inline FoldBack (x, f, z) = 34 | let rec _foldMap x f = 35 | match x with 36 | | Empty -> getEmpty() 37 | | Leaf n -> f n 38 | | Node (l,k,r) -> append (_foldMap l f) (append (f k) (_foldMap r f)) 39 | Endo.run (_foldMap x (Endo << f )) z 40 | 41 | 42 | let tree = Node (Node (Leaf 1, 6, Leaf 3), 2 , Leaf 9) 43 | let res21 = foldBack (+) tree 0 44 | // Uses the default method: 45 | let res21' = fold (+) 0 tree 46 | let resTr = exists ((=) 3) tree 47 | let resS3 = tryPick (fun x -> if x = 3 then Some x else None) tree 48 | 49 | type ZipList<'s> = ZipList of 's seq with 50 | static member Return (x:'a) = ZipList (Seq.initInfinite (konst x)) 51 | static member Map (ZipList x, f:'a->'b) = ZipList (Seq.map f x) 52 | static member (<*>) (ZipList (f:seq<'a->'b>), ZipList x) = ZipList (Seq.zip f x |> Seq.map (fun (f,x) -> f x)) :ZipList<'b> 53 | static member inline get_Empty() = result (getEmpty()) :ZipList<'a> 54 | static member inline Append (x:ZipList<'a>, y:ZipList<'a>) = liftA2 append x y :ZipList<'a> 55 | // try also commenting/uncommenting the following method. 56 | static member inline Concat (x:seq>) = printfn "ZipList mconcat optimized (in theory)"; List.foldBack append (Seq.toList x) (getEmpty()):ZipList<'a> 57 | static member ToSeq (ZipList lst) = lst 58 | 59 | type WrappedList<'s> = WrappedList of 's list with 60 | static member Return (_:WrappedList<'a>, _:Return ) = fun (x:'a) -> WrappedList [x] 61 | static member Append (WrappedList l, WrappedList x) = WrappedList (l @ x) 62 | static member Empty (_:WrappedList<'a>, _:Empty) = WrappedList List.empty 63 | static member ToSeq (WrappedList lst) = List.toSeq lst 64 | static member FoldBack (WrappedList x, f, z) = List.foldBack f x z 65 | 66 | let wl = WrappedList [2..10] 67 | 68 | let threes = filter ((=) 3) [ 1;2;3;4;5;6;1;2;3;4;5;6 ] 69 | let fours = filter ((=) 4) [|1;2;3;4;5;6;1;2;3;4;5;6|] 70 | let twos = filter ((=) (box 2)) (([1;2;3;4;3;2;1;2;3] |> ofSeq) : Collections.ArrayList) 71 | let five = filter ((=) 5) (WrappedList [1;2;3;4;5;6]) // <- Uses the default method for filter. 72 | let sorted = sortBy (~-) (WrappedList [1;2;3;4;5;6]) 73 | let optionFilter = filter ((=) 3) (Some 4) 74 | 75 | let arrayGroup = groupBy ((%)/> 2) [|11;2;3;9;5;6;7;8;9;10|] 76 | let listGroup = groupBy ((%)/> 2) [ 11;2;3;9;5;6;7;8;9;10 ] 77 | let seqGroup = groupBy ((%)/> 2) (seq [11;2;3;9;5;6;7;8;9;10]) 78 | 79 | let arrayGroupAdj = chunkBy ((%)/> 2) [11;2;3;9;5;6;7;8;9;10] 80 | 81 | let sortedList = sortBy string [ 11;2;3;9;5;6;7;8;9;10 ] 82 | let sortedSeq = sortBy string (seq [11;2;3;9;5;6;7;8;9;10]) 83 | 84 | let bigSeq = seq {1..10000000} 85 | let bigLst = [ 1..10000000 ] 86 | let bigArr = [|1..10000000|] 87 | let bigMut = ResizeArray(seq {1..10000000}) 88 | 89 | let x = head bigSeq 90 | let y = head bigLst 91 | let z = head bigArr 92 | 93 | let a = skip 1000 bigSeq 94 | let b = skip 1000 bigLst 95 | let c = skip 1000 bigArr 96 | let d = skip 1000 bigMut 97 | let e = "hello world" |> skip 6 |> toList 98 | let h = ofList ['h';'e';'l';'l';'o';' '] + "world" 99 | let i = item 2 bigSeq 100 | let j = item 2 "hello" 101 | 102 | 103 | // Monoids 104 | 105 | let asQuotation = append <@ ResizeArray(["1"]) @> <@ ResizeArray(["2;3"]) @> 106 | let quot123 = append <@ ResizeArray([1]) @> <@ ResizeArray([2;3]) @> 107 | let quot1 = append <@ ResizeArray([1]) @> (getEmpty()) 108 | let quot23 = append (getEmpty()) <@ ResizeArray([2;3]) @> 109 | let quot13 = append (getEmpty()) <@ ("1","3") @> 110 | let quotLst123 = append (getEmpty()) (ZipList [ [1];[2];[3] ]) 111 | let quotLst123' = concat [getEmpty(); getEmpty(); ZipList [ [1];[2];[3] ]] 112 | 113 | let lzy1 = append (lazy [1]) (lazy [2;3]) 114 | let lzy2 = append (getEmpty()) lzy1 115 | let asy1 = append (async.Return [1]) (async.Return [2;3]) 116 | let asy2 = append (getEmpty()) asy1 117 | 118 | let mapA = Map.empty 119 | |> Map.add 1 (async.Return "Hey") 120 | |> Map.add 2 (async.Return "Hello") 121 | 122 | let mapB = Map.empty 123 | |> Map.add 3 (async.Return " You") 124 | |> Map.add 2 (async.Return " World") 125 | 126 | let mapAB = append mapA mapB 127 | let greeting1 = Async.RunSynchronously mapAB.[2] 128 | let greeting2 = Async.RunSynchronously (concat [mapA; getEmpty(); mapB]).[2] 129 | 130 | open System.Collections.Generic 131 | open System.Threading.Tasks 132 | 133 | let dicA = new Dictionary>() 134 | dicA.["keya"] <- (result "Hey" : Task<_>) 135 | dicA.["keyb"] <- (result "Hello": Task<_>) 136 | 137 | let dicB = new Dictionary>() 138 | dicB.["keyc"] <- (result " You" : Task<_>) 139 | dicB.["keyb"] <- (result " World": Task<_>) 140 | 141 | let dicAB = append dicA dicB 142 | 143 | let greeting3 = extract dicAB.["keyb"] 144 | let greeting4 = extract (concat [dicA; getEmpty(); dicB]).["keyb"] 145 | 146 | let res2 = concat [ async {return Endo ((+) 2)} ; async {return Endo ((*) 10)} ; async {return Endo id } ; async {return Endo ((%) 3)} ; async {return getEmpty() } ] |> Async.RunSynchronously |> Endo.run <| 3 147 | let res330 = concat [ async {return (fun (x:int) -> string x)} ; async {return (fun (x:int) -> string (x*10))} ; async {return getEmpty() } ] 3 148 | 149 | // Functors, Monads 150 | 151 | let quot7 = map ((+)2) <@ 5 @> 152 | let (quot5:Microsoft.FSharp.Quotations.Expr) = result 5 153 | 154 | // Do notation 155 | type MonadBuilder() = 156 | member inline b.Return(x) = result x 157 | member inline b.Bind(p,rest) = p >>= rest 158 | member b.Let (p,rest) = rest p 159 | member b.ReturnFrom(expr) = expr 160 | member inline b.Delay(expr:unit -> 't) = FsControl.Delay.Invoke(expr) : 't 161 | let monad = new MonadBuilder() 162 | 163 | 164 | // Indexables 165 | 166 | let namesWithNdx = mapi (fun k v -> "(" + string k + ")" + v ) (Map.ofSeq ['f',"Fred";'p',"Paul"]) 167 | let namesAction = iteri (printfn "(%A)%s") (Map.ofSeq ['f',"Fred";'p',"Paul"]) 168 | let res119 = foldi (fun s i t-> t * s - i) 10 [3;4] 169 | let res113 = foldi (fun s i t-> t * s - i) 2 [|3;4;5|] 170 | let resSomeId20 = traversei (fun k t -> Some (10 + t)) (Tuple 10) 171 | 172 | 173 | // Seq 174 | 175 | let stack = new Collections.Generic.Stack<_>([1;2;3]) 176 | 177 | let twoSeqs = append (seq [1;2;3]) (seq [4;5;6]) 178 | let sameSeq = append (getEmpty() ) (seq [4;5;6]) 179 | 180 | let seqFromLst:_ seq = ofList [1;2;3;4] 181 | let seqFromLst' = toSeq [1;2;3;4] 182 | let seqFromOpt = toSeq (Some 1) 183 | 184 | // This should not compile 185 | (* 186 | let twoStacks = append stack stack 187 | let twoSeqs' = append (seq [1;2;3]) [4;5;6] 188 | let twoSeqs'' = append [1;2;3] (seq [4;5;6]) 189 | let (stackFromLst:_ Collections.Generic.Stack) = ofList [1;2;3;4] 190 | *) 191 | 192 | let singletonList: _ list = result 1 193 | let singletonSeq : _ seq = result 1 194 | 195 | 196 | // This should not compile (but it does) 197 | (* 198 | let sortedStack = sortBy string stack // <- cool, now it fails 199 | *) 200 | let mappedstack = map string stack 201 | let stackGroup = groupBy ((%)/> 2) stack 202 | 203 | 204 | // Test Seq Monad 205 | 206 | let rseq = 207 | monad { 208 | let! x1 = seq [1;2] 209 | let! x2 = seq [10;20] 210 | return ((+) x1 x2) } 211 | 212 | 213 | // Test Seq Comonad 214 | 215 | let lst = seq [1;2;3;4;5] 216 | let elem1 = head lst 217 | let tails = duplicate lst 218 | let lst' = extend head lst 219 | 220 | (* Should fail 221 | let tails' = duplicate stack 222 | let stk' = extend head stack 223 | *) 224 | 225 | // Test foldable 226 | 227 | let r10 = foldBack (+) (seq [1;2;3;4]) 0 228 | let r323 = toList (seq [3;2;3]) 229 | let r03 = filter ((=) 3) (seq [1;2;3]) 230 | 231 | // This should not compile ??? (but it does) 232 | let r10' = foldBack (+) stack 0 233 | let r123 = toList stack 234 | 235 | let r03' = filter ((=) 3) stack 236 | 237 | // Test traversable 238 | 239 | let resNone = traverse (fun x -> if x > 4 then Some x else None) (Seq.initInfinite id) // optimized method, otherwise it doesn't end 240 | let resNone' = sequenceA (seq [Some 3;None ;Some 1]) 241 | 242 | // This should not compile (but it does) 243 | let resNone'' = sequenceA (new Collections.Generic.Stack<_>([Some 3;None ;Some 1])) 244 | 245 | 246 | 247 | let getLine = async { return System.Console.ReadLine() } 248 | let putStrLn x = async { printfn "%s" x} 249 | 250 | let inline sequence ms = 251 | let k m m' = m >>= fun (x:'a) -> m' >>= fun (xs:seq<'a>) -> (result :seq<'a> -> 'M) (seq {yield x; yield! xs}) 252 | Array.foldBack k (Seq.toArray ms) ((result :seq<'a> -> 'M) (Seq.empty)) 253 | 254 | let inline mapM f as' = sequence (Seq.map f as') 255 | 256 | type DoPlusNotationBuilder() = 257 | member inline b.Return(x) = result x 258 | member inline b.Bind(p,rest) = p >>= rest 259 | member b.Let(p,rest) = rest p 260 | member b.ReturnFrom(expr) = expr 261 | member inline x.Zero() = getMZero() 262 | member inline x.Combine(a, b) = a <|> b 263 | member inline b.Delay(expr:unit -> 't) = FsControl.Delay.Invoke(expr) : 't 264 | let doPlus = new DoPlusNotationBuilder() 265 | 266 | // Test MonadPlus 267 | let nameAndAddress = mapM (fun x -> putStrLn x >>= fun _ -> getLine) (seq ["name";"address"]) 268 | 269 | // this compiles but it requires a type annotation to tell between 270 | // seq and other monadplus #seq types 271 | let pythags = monad { 272 | let! z = seq [1..50] 273 | let! x = seq [1..z] 274 | let! y = seq [x..z] 275 | do! (guard (x*x + y*y = z*z) : _ seq) 276 | return (x, y, z)} 277 | 278 | 279 | let pythags' = doPlus{ 280 | let! z = seq [1..50] 281 | let! x = seq [1..z] 282 | let! y = seq [x..z] 283 | if (x*x + y*y = z*z) then return (x, y, z)} 284 | 285 | let res123123 = (seq [1;2;3]) <|> (seq [1;2;3]) 286 | let allCombinations = sequence (seq [seq ['a';'b';'c']; seq ['1';'2']]) //|> Seq.map Seq.toList |> Seq.toList -------------------------------------------------------------------------------- /FsControl.Core/Samples/Converter.fsx: -------------------------------------------------------------------------------- 1 | #nowarn "3186" 2 | #r @"..\bin\Release\FsControl.dll" 3 | 4 | open System 5 | open FsControl.Operators 6 | 7 | let r101 = tryParse "10.1.0.1" : Net.IPAddress option 8 | let r102 = tryParse "102" : string option 9 | let rMTS = [tryParse "Monday" ; Some DayOfWeek.Thursday; Some DayOfWeek.Saturday] 10 | let r103 = tryParse "103" : Text.StringBuilder option 11 | 12 | let r109 = parse "10.0.9.1" : Net.IPAddress 13 | let r111 = parse "true" && true 14 | let rMTF = [parse "Monday" ; DayOfWeek.Thursday; DayOfWeek.Friday] 15 | let r110 = parse "10" + ofBytes [|10uy;0uy;0uy;0uy;0uy;0uy;0uy;0uy|] + 100. 16 | let r120 = parse "10" + ofBytes [|10uy;0uy;0uy;0uy;|] + 100 17 | let r121 = parse "121" : string 18 | let r122 = parse "122" : Text.StringBuilder 19 | 20 | let r123 = toString [1;2;3] 21 | let r140 = toString (1,4,0) 22 | let r150 = toString (Some 150) 23 | let r160 = toString ([1;6;0] :> _ seq) 24 | let r170 = toString (ResizeArray([1;7;0])) 25 | let r180 = toString (Set [1;8;0]) 26 | let r190 = toString [|1;9;0|] 27 | let r200 = toString [|{1..3};{4..6};{7..9}|] 28 | let r210 = toString (Map ['a',2; 'b',1; 'c',0]) 29 | let r220 = toString (dict ['a',2; 'b',2; 'c',0]) 30 | 31 | 32 | // Generic op_Explicit 33 | let r302:float = explicit 302 34 | let r303:float = explicit "303" 35 | let r304:char = explicit "F" 36 | 37 | 38 | // From sequence 39 | open System.Collections 40 | open System.Collections.Concurrent 41 | open System.Collections.Generic 42 | 43 | let sk :Generic.Stack<_> = ofSeq { 1 .. 3 } 44 | let sg :string = ofSeq {'1'..'3'} // but it will come back as seq 45 | let sb :Text.StringBuilder = ofSeq {'1'..'3'} // but it will come back as seq 46 | let sq1:_ seq = ofSeq { 1 .. 3 } 47 | let sq2:_ seq = ofSeq (seq [(1, "One"); (2, "Two")]) 48 | let sq3:_ seq = ofSeq (seq [(1, "One", '1'); (2, "Two", '2')]) 49 | let sq4:_ seq = ofSeq (seq [(1, "One", '1', 1M); (2, "Two", '2', 2M)]) 50 | let ls1:_ list = ofSeq {'1'..'3'} 51 | let ls2:_ list = ofSeq (seq [(1, "One", '1'); (2, "Two", '2')]) 52 | let st1:_ Set = ofSeq {'1'..'3'} 53 | let st2:_ Set = ofSeq (seq [(1, "One", '1'); (2, "Two", '2')]) 54 | let ss :Generic.SortedSet<_> = ofSeq (seq [3..6]) 55 | let ra :Generic.List<_> = ofSeq (seq [1..3]) 56 | let sl :Generic.SortedList<_,_> = ofSeq (seq [(1, "One"); (2, "Two")]) // but it will come back as ... 57 | let sl2:Generic.SortedList<_,_> = ofSeq (seq [KeyValuePair(1, "One"); KeyValuePair(2, "Two")]) 58 | let dc :Generic.Dictionary<_,_> = ofSeq (seq [(1, "One"); (2, "Two")]) // but it will come back as kKeyValuePair 59 | let mp :Map<_,_> = ofSeq (seq [(1, "One"); (2, "Two")]) // but it will come back as ... 60 | let mp2:Map<_,_> = ofSeq (seq [KeyValuePair(1, "One"); KeyValuePair(2, "Two")]) 61 | let d :Generic.IDictionary<_,_> = ofSeq (seq [("One", 1)]) // but it will come back as ... 62 | let d2 :Generic.IDictionary<_,_> = ofSeq (seq [KeyValuePair(1, "One"); KeyValuePair(2, "Two")]) 63 | let ut :Hashtable = ofSeq (seq [1,'1';2, '2';3,'3']) // but it will come back as seq 64 | let al :ArrayList = ofSeq (seq ["1";"2";"3"]) // but it will come back as seq 65 | let us :SortedList = ofSeq (seq [4,'2';3,'4']) // but it will come back as seq 66 | let cc :BlockingCollection<_> = ofSeq {'1'..'3'} // but it will come back as seq 67 | let cd :ConcurrentDictionary<_,_> = ofSeq (seq [(1, "One"); (2, "Two")]) // but it will come back as ... 68 | let cd2:ConcurrentDictionary<_,_> = ofSeq (seq [KeyValuePair(1, "One"); KeyValuePair(2, "Two")]) 69 | let cb :ConcurrentBag<_> = ofSeq {'1'..'3'} 70 | 71 | // now go back 72 | let sk' = toSeq sk 73 | let sg' = toSeq sg 74 | let sb' = toSeq sb 75 | let sq1' = toSeq sq1 76 | let sq2' = toSeq sq2 77 | let sq3' = toSeq sq3 78 | let sq4' = toSeq sq4 79 | let ls1' = toSeq ls1 80 | let ls2' = toSeq ls2 81 | let st1' = toSeq st1 82 | let st2' = toSeq st2 83 | let ss' = toSeq ss 84 | let ra' = toSeq ra 85 | let sl' = toSeq sl 86 | let dc' = toSeq dc 87 | let mp' = toSeq mp 88 | let d' = toSeq d 89 | let ut' = toSeq ut 90 | let al' = toSeq al 91 | let us' = toSeq us 92 | let cc' = toSeq cc 93 | let cd' = toSeq cd 94 | let cb' = toSeq cb 95 | 96 | // there are some 'one-way' collections that can only be converted toSeq 97 | 98 | let columns = 99 | let d = new Data.DataTable() 100 | [|new Data.DataColumn "id";new Data.DataColumn "column1";new Data.DataColumn "column2"|] |> d.Columns.AddRange 101 | d.Columns 102 | let col1 = columns |> find (fun x -> x.ColumnName = "column1") 103 | let cols = columns |> toList |> map (fun x -> x.ColumnName) -------------------------------------------------------------------------------- /FsControl.Core/Samples/Functions.fsx: -------------------------------------------------------------------------------- 1 | #nowarn "3186" 2 | #r @"..\bin\Release\FsControl.dll" 3 | 4 | // FsControl does not automatically export any function, just the 'Type Methods'. 5 | // However in the FsControl.Operators module there are some function and operator definitions. 6 | // The main purpose of that module is to make tests easier, without having to reapeat code or rely on another library to make simple tests. 7 | 8 | open FsControl.Operators 9 | 10 | let inline flip f x y = f y x 11 | let inline konst k _ = k 12 | let inline () x 13 | let inline (/>) x = flip x 14 | let inline choice f g = function Choice2Of2 x -> f x | Choice1Of2 y -> g y 15 | let inline option n f = function None -> n | Some x -> f x 16 | 17 | 18 | // Test Functors 19 | let times2,minus3 = (*) 2, (-)/> 3 20 | let resJust1 = map minus3 (Some 4) 21 | let noValue = map minus3 None 22 | let lstTimes2 = map times2 [1;2;3;4] 23 | let fTimes2minus3 = map minus3 times2 24 | let res39 = fTimes2minus3 21 25 | let res3n4 = result ((+) 2) <*> [1;2] 26 | 27 | 28 | 29 | // test numbers 30 | 31 | let qr0 = divRem 7 3 //val qr0 : int * int = (2, 1) 32 | let qr1 = divRem 7I 3I //val qr1 : System.Numerics.BigInteger * System.Numerics.BigInteger = (2, 1) 33 | let qr2 = divRem 7. 3. //val qr2 : float * float = (2.333333333, 0.0) -> using default method. 34 | 35 | let inline findMin (lst: 'a list) = 36 | let minValue, maxValue = minValue(), maxValue() 37 | let rec loop acc = function 38 | | [] -> acc 39 | | x::_ when x = minValue -> x 40 | | x::xs -> loop (if x < acc then x else acc) xs 41 | loop maxValue lst 42 | 43 | let minInt = findMin [1;0;12;2] 44 | let minUInt = findMin [1u;0u;12u;2u] // loops only twice 45 | 46 | 47 | 48 | 49 | // Test Extension Methods 50 | open FsControl 51 | 52 | let mapp1 = [1..3] [4..8] 53 | let mapp2 = [1..3] .Append [4..8] 54 | let mcon1 = [|[|1..3|];[|4..5|]|] |> join 55 | let mcon2 = [|[|1..3|];[|4..5|]|] .Join(null, Unchecked.defaultof) // optional arguments don't work from F# 56 | // but in C# you can write (new[] {new[] {1, 2, 3}, new[] {4, 5, 6}}).Join(); -------------------------------------------------------------------------------- /FsControl.Core/Samples/Numerics.fsx: -------------------------------------------------------------------------------- 1 | #nowarn "3186" 2 | #r @"..\bin\Release\FsControl.dll" 3 | 4 | open FsControl.Operators 5 | 6 | let flip f x y = f y x 7 | let const' k _ = k 8 | 9 | let () 10 | let (/>) = flip 11 | 12 | 13 | 14 | // Numerics 15 | type Integer = bigint 16 | open System.Numerics 17 | open FsControl 18 | 19 | let inline fromInteger (x:Integer) :'Num = FsControl.Operators.fromBigInt x 20 | let inline toInteger (x:'Integral) :Integer = FsControl.Operators.toBigInt x 21 | let inline fromIntegral (x:'Integral) :'Num = (fromInteger << toInteger) x 22 | 23 | module NumericLiteralG = 24 | let inline FromZero() = Zero.Invoke() 25 | let inline FromOne () = One.Invoke() 26 | let inline FromInt32 (i:int ) = FromInt32.Invoke i 27 | let inline FromInt64 (i:int64 ) = FromInt64.Invoke i 28 | let inline FromString (i:string) = fromInteger <| BigInteger.Parse i 29 | 30 | 31 | 32 | 33 | let inline whenIntegral a = let _ = if false then toInteger a else 0I in () 34 | 35 | 36 | module Ratio = 37 | // Strict version of math operators 38 | let inline internal ( +.) (a:'Num) (b:'Num) :'Num = a + b 39 | let inline internal ( -.) (a:'Num) (b:'Num) :'Num = a - b 40 | let inline internal ( *.) (a:'Num) (b:'Num) :'Num = a * b 41 | 42 | let inline internal gcd x y :'Integral = 43 | let zero = getZero() 44 | let rec loop a b = 45 | if b = zero then a 46 | else loop b (a % b) 47 | if (x, y) = (zero, zero) then failwith "gcd 0 0 is undefined" 48 | else loop (Abs.Invoke x) (Abs.Invoke y) 49 | 50 | type Ratio<'Integral> = 51 | struct 52 | val Numerator :'Integral 53 | val Denominator :'Integral 54 | new (numerator: 'Integral, denominator: 'Integral) = {Numerator = numerator; Denominator = denominator} 55 | end 56 | override this.ToString() = this.Numerator.ToString() + " % " + this.Denominator.ToString() 57 | 58 | let inline internal ratio (a:'Integral) (b:'Integral) :Ratio<'Integral> = 59 | whenIntegral a 60 | let zero = getZero() 61 | if b = zero then failwith "Ratio.%: zero denominator" 62 | let (a, b) = if b < zero then (-a, -b) else (a, b) 63 | let gcd = gcd a b 64 | Ratio (a / gcd, b / gcd) 65 | 66 | let inline internal Ratio (x,y) = x y 67 | 68 | let inline internal numerator (r:Ratio<_>) = r.Numerator 69 | let inline internal denominator (r:Ratio<_>) = r.Denominator 70 | 71 | type Ratio<'Integral> with 72 | static member inline (/) (a:Ratio<_>, b:Ratio<_>) = (a.Numerator *. b.Denominator) (a.Denominator *. b.Numerator) 73 | static member inline (+) (a:Ratio<_>, b:Ratio<_>) = (a.Numerator *. b.Denominator +. b.Numerator *. a.Denominator) (a.Denominator *. b.Denominator) 74 | static member inline (-) (a:Ratio<_>, b:Ratio<_>) = (a.Numerator *. b.Denominator -. b.Numerator *. a.Denominator) (a.Denominator *. b.Denominator) 75 | static member inline (*) (a:Ratio<_>, b:Ratio<_>) = (a.Numerator *. b.Numerator) (a.Denominator *. b.Denominator) 76 | 77 | static member inline Abs (r:Ratio<_>) = (Abs.Invoke (numerator r)) (denominator r) 78 | static member inline Signum (r:Ratio<_>) = (Signum.Invoke (numerator r)) (One.Invoke()) 79 | static member inline FromBigInt (x:bigint) = FromBigInt.Invoke x (One.Invoke()) 80 | static member inline (~-) (r:Ratio<_>) = -(numerator r) (denominator r) 81 | 82 | 83 | let (|Ratio|) (ratio:Ratio<_>) = (ratio.Numerator, ratio.Denominator) 84 | 85 | type Rational = Ratio.Ratio 86 | 87 | 88 | 89 | 90 | let inline abs (x:'Num) :'Num = FsControl.Operators.abs x 91 | let inline signum (x:'Num) :'Num = FsControl.Operators.signum x 92 | 93 | let inline (+) (a:'Num) (b:'Num) :'Num = a + b 94 | let inline (-) (a:'Num) (b:'Num) :'Num = a - b 95 | let inline (*) (a:'Num) (b:'Num) :'Num = a * b 96 | 97 | let inline negate (x:'Num) :'Num = FsControl.Operators.negate x 98 | let inline (~-) (x:'Num) :'Num = FsControl.Operators.negate x 99 | 100 | 101 | let inline div (a:'Integral) b :'Integral = 102 | whenIntegral a 103 | let (a,b) = if b < 0G then (-a,-b) else (a,b) 104 | (if a < 0G then (a - b + 1G) else a) / b 105 | 106 | let inline quot (a:'Integral) (b:'Integral) :'Integral = whenIntegral a; a / b 107 | let inline rem (a:'Integral) (b:'Integral) :'Integral = whenIntegral a; a % b 108 | let inline quotRem a b :'Integral * 'Integral = whenIntegral a; FsControl.Operators.divRem a b 109 | let inline mod' a b :'Integral = whenIntegral a; ((a % b) + b) % b 110 | let inline divMod D d :'Integral * 'Integral = 111 | let q, r = quotRem D d 112 | if (r < 0G) then 113 | if (d > 0G) then (q - 1G, r + d) 114 | else (q + 1G, r - d) 115 | else (q, r) 116 | 117 | 118 | 119 | 120 | 121 | let inline (/) (a:'Fractional) (b:'Fractional) :'Fractional = (* whenFractional a;*) a / b 122 | let inline recip x :'Fractional = 1G / x 123 | 124 | // Exp functions 125 | let inline ( **^ ) (x:'Num) (n:'Integral) = 126 | whenIntegral n 127 | let rec f a b n = if n == 0G then a else f (b * a) b (n - 1G) 128 | if (n < 0G) then failwith "Negative exponent" else f 1G x n 129 | let inline ( **^^ ) (x:'Fractional) (n:'Integral) = if n >= 0G then x**^n else recip (x**^(negate n)) 130 | 131 | let inline pi() :'Floating = FsControl.Operators.getPi () 132 | 133 | let inline ( **) a (b:'Floating) :'Floating = a ** b 134 | 135 | let inline asinh x :'Floating = log (x + sqrt (1G+x*x)) 136 | let inline acosh x :'Floating = log (x + (x+1G) * sqrt ((x-1G)/(x+1G))) 137 | let inline atanh x :'Floating = (1G/2G) * log ((1G+x) / (1G-x)) 138 | 139 | let inline logBase x y :'Floating = log y / log x 140 | 141 | 142 | // Test Numerics 143 | 144 | let piComplex:System.Numerics.Complex = pi() 145 | 146 | let c2 = System.Numerics.Complex(25.2, 3.1) 147 | 148 | let a = abs' 2u 149 | let b = abs' -2 150 | let c = abs' -2.f 151 | let d = abs' -2.M 152 | let e = abs' c2 153 | let f = abs' (System.Numerics.Complex(32. , 2.)) 154 | 155 | let a' = signum' 2u 156 | let b' = signum' -2 157 | let c' = signum' -2.f 158 | let d' = signum' -2.M 159 | let e' = signum' c2 160 | let f' = signum' (System.Numerics.Complex(32. , 2.)) 161 | 162 | 163 | let divisions = List.map ( quot /> 5G) [5;8;10;15;20] 164 | 165 | let inline quadratic a b c = 166 | let root1 = ( -b + sqrt ( b * b - 4G * a * c) ) / (2G * a) 167 | let root2 = ( -b - sqrt ( b * b - 4G * a * c) ) / (2G * a) 168 | (root1,root2) 169 | 170 | let res30_15 = quadratic 2.0 -3G -9G 171 | let res30_15f = quadratic 2.0f -3G -9G 172 | 173 | let resCmplx:System.Numerics.Complex * _ = quadratic 2G -3G 9G 174 | 175 | (* Warning, works but very slow compile time with current version of F# 176 | let res30_15r:Rational * _ = quadratic 2G -3G -9G 177 | *) -------------------------------------------------------------------------------- /FsControl.Core/Traversable.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open System.Runtime.CompilerServices 4 | open System.Runtime.InteropServices 5 | open FsControl.Internals 6 | open FsControl.Internals.Prelude 7 | open FsControl.Internals.MonadOps 8 | 9 | 10 | type Traverse = 11 | inherit Default1 12 | static member inline Traverse (t:^a , f, []output:'R, []impl:Default3 ) = Map.Invoke f ((^a) : (static member SequenceA: _ -> 'R) t) 13 | static member inline Traverse (t:^a , f, []output:'R, []impl:Default2 ) = ((^a) : (static member Traverse: _*_ -> 'R) t, f) 14 | static member inline Traverse (t:Id<_>, f, []output:'R, []impl:Default1) = Map.Invoke Id.create (f (Id.run t)) 15 | static member inline Traverse (t:_ seq, f, []output:'R, []impl:Default1) = 16 | let cons x y = seq {yield x; yield! y} 17 | let cons_f x ys = Map.Invoke (cons:'a->seq<_>->seq<_>) (f x) <*> ys 18 | Seq.foldBack cons_f t (result (Seq.empty)) 19 | 20 | static member Traverse (t:'t seq ,f:'t->'u option , []output:option>, []impl:Traverse) = 21 | let ok = ref true 22 | let res = Seq.toArray (seq { 23 | use e = t.GetEnumerator() 24 | while (e.MoveNext() && ok.Value) do 25 | match f e.Current with 26 | | Some v -> yield v 27 | | None -> ok.Value <- false}) 28 | if ok.Value then Some (Array.toSeq res) else None 29 | 30 | static member Traverse (t:'t seq ,f:'t->Async<'u> , []output:Async>, []impl:Traverse) :Async> = result <| Seq.map (Async.RunSynchronously) (Seq.map f t) 31 | static member Traverse (t:Id<'t> ,f:'t->option<'u> , []output:option>, []impl:Traverse) = Option.map Id.create (f (Id.run t)) 32 | static member inline Traverse (t:option<_>,f , []output:'R , []impl:Traverse) :'R = match t with Some x -> Map.Invoke Some (f x) | _ -> result None 33 | 34 | static member inline Traverse (t:list<_> ,f , []output:'R , []impl:Traverse) :'R = 35 | let cons_f x ys = Map.Invoke List.cons (f x) <*> ys 36 | List.foldBack cons_f t (result []) 37 | 38 | static member inline Traverse (t:_ [] ,f , []output :'R , []impl:Traverse) :'R = 39 | let cons x y = Array.append [|x|] y 40 | let cons_f x ys = Map.Invoke cons (f x) <*> ys 41 | Array.foldBack cons_f t (result [||]) 42 | 43 | static member inline Invoke f t = 44 | let inline call_3 (a:^a, b:^b, c:^c, f) = ((^a or ^b or ^c) : (static member Traverse: _*_*_*_ -> _) b, f, c, a) 45 | let inline call (a:'a, b:'b, f) = call_3 (a, b, Unchecked.defaultof<'R>, f) :'R 46 | call (Unchecked.defaultof, t, f) 47 | 48 | 49 | [] 50 | type SequenceA = 51 | inherit Default1 52 | []static member inline SequenceA (t:^a , []output:'R, []impl:Default2 ) = ((^a) : (static member Traverse: _*_ -> 'R) t, id) :'R 53 | []static member inline SequenceA (t:^a , []output:'R, []impl:Default1 ) = ((^a) : (static member SequenceA: _ -> 'R) t) :'R 54 | []static member inline SequenceA (t:option<_> , []output:'R, []impl:SequenceA) = match t with Some x -> Map.Invoke Some x | _ -> result None :'R 55 | []static member inline SequenceA (t:list<_> , []output:'R, []impl:SequenceA) = let cons_f x ys = Map.Invoke List.cons x <*> ys in List.foldBack cons_f t (result []) :'R 56 | []static member inline SequenceA (t:_ [] , []output:'R, []impl:SequenceA) = let cons x y = Array.append [|x|] y in let cons_f x ys = Map.Invoke cons x <*> ys in Array.foldBack cons_f t (result [||]) :'R 57 | []static member inline SequenceA (t:Id<_> , []output:'R, []impl:SequenceA) = Traverse.Invoke id t :'R 58 | []static member inline SequenceA (t: _ ResizeArray, []output:'R, []impl:SequenceA) = Traverse.Invoke id t :'R 59 | []static member inline SequenceA (t:_ seq , []output:'R, []impl:SequenceA) :'R = 60 | let cons x y = seq {yield x; yield! y} 61 | let cons_f x ys = Map.Invoke (cons:'a->seq<_>->seq<_>) x <*> ys 62 | Seq.foldBack cons_f t (result Seq.empty) 63 | 64 | static member inline Invoke (t:'Traversable'Applicative'T) :'Applicative'Traversable'T = 65 | let inline call_3 (a:^a, b:^b, c:^c) = ((^a or ^b or ^c) : (static member SequenceA: _*_*_ -> _) b, c, a) 66 | let inline call (a:'a, b:'b) = call_3 (a, b, Unchecked.defaultof<'R>) :'R 67 | call (Unchecked.defaultof, t) -------------------------------------------------------------------------------- /FsControl.Core/Tuple.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl 2 | 3 | open System 4 | open System.Text 5 | open System.Runtime.CompilerServices 6 | open System.Runtime.InteropServices 7 | open FsControl.Internals 8 | 9 | 10 | [] 11 | type Item1 = 12 | []static member inline Item1 (t :'a ) = ((^a) : (member Item1: _ ) t) 13 | []static member Item1 ((a, b, c, d, e)) = a 14 | []static member Item1 ((a, b, c, d) ) = a 15 | []static member Item1 ((a, b, c) ) = a 16 | []static member Item1 ((a, b) ) = a 17 | 18 | static member inline Invoke value = 19 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Item1: _ -> _) b) 20 | let inline call (a:'a, b:'b) = call_2 (a, b) 21 | call (Unchecked.defaultof , value) 22 | 23 | [] 24 | type Item2 = 25 | []static member inline Item2 (t :'a ) = ((^a) : (member Item2: _ ) t) 26 | []static member Item2 ((a, b, c, d, e)) = b 27 | []static member Item2 ((a, b, c, d) ) = b 28 | []static member Item2 ((a, b, c) ) = b 29 | []static member Item2 ((a, b) ) = b 30 | 31 | static member inline Invoke value = 32 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Item2: _ -> _) b) 33 | let inline call (a:'a, b:'b) = call_2 (a, b) 34 | call (Unchecked.defaultof , value) 35 | 36 | [] 37 | type Item3 = 38 | []static member inline Item3 (t :'a ) = ((^a) : (member Item3: _ ) t) 39 | []static member Item3 ((a, b, c, d, e)) = c 40 | []static member Item3 ((a, b, c, d) ) = c 41 | []static member Item3 ((a, b, c) ) = c 42 | 43 | static member inline Invoke value = 44 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Item3: _ -> _) b) 45 | let inline call (a:'a, b:'b) = call_2 (a, b) 46 | call (Unchecked.defaultof , value) 47 | 48 | [] 49 | type Item4 = 50 | []static member inline Item4 (t :'a ) = ((^a) : (member Item4: _ ) t) 51 | []static member Item4 ((a, b, c, d, e)) = d 52 | []static member Item4 ((a, b, c, d) ) = d 53 | 54 | static member inline Invoke value = 55 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Item4: _ -> _) b) 56 | let inline call (a:'a, b:'b) = call_2 (a, b) 57 | call (Unchecked.defaultof , value) 58 | 59 | [] 60 | type Item5 = 61 | []static member inline Item5 (t :'a ) = ((^a) : (member Item5: _ ) t) 62 | []static member Item5 ((a, b, c, d, e)) = e 63 | 64 | static member inline Invoke value = 65 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member Item5: _ -> _) b) 66 | let inline call (a:'a, b:'b) = call_2 (a, b) 67 | call (Unchecked.defaultof , value) 68 | 69 | 70 | type MapItem1 = 71 | static member MapItem1 ((a, b, c, d, e) , fn) = (fn a, b, c, d, e) 72 | static member MapItem1 ((a, b, c, d) , fn) = (fn a, b, c, d) 73 | static member MapItem1 ((a, b, c) , fn) = (fn a, b, c) 74 | static member MapItem1 ((a, b) , fn) = (fn a, b) 75 | 76 | static member inline Invoke f value = 77 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member MapItem1: _ * _ -> _) b, f) 78 | let inline call (a:'a, b:'b) = call_2 (a, b) 79 | call (Unchecked.defaultof , value) 80 | 81 | [] 82 | type MapItem2 = 83 | static member MapItem2 ((a, b, c, d, e) , fn) = (a, fn b, c, d, e) 84 | static member MapItem2 ((a, b, c, d) , fn) = (a, fn b, c, d) 85 | static member MapItem2 ((a, b, c) , fn) = (a, fn b, c) 86 | static member MapItem2 ((a, b) , fn) = (a, fn b) 87 | 88 | static member inline Invoke f value = 89 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member MapItem2: _ * _ -> _) b, f) 90 | let inline call (a:'a, b:'b) = call_2 (a, b) 91 | call (Unchecked.defaultof , value) 92 | 93 | type MapItem3 = 94 | static member MapItem3 ((a, b, c, d, e) , fn) = (a, b, fn c, d, e) 95 | static member MapItem3 ((a, b, c, d) , fn) = (a, b, fn c, d) 96 | static member MapItem3 ((a, b, c) , fn) = (a, b, fn c) 97 | 98 | static member inline Invoke f value = 99 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member MapItem3: _ * _ -> _) b, f) 100 | let inline call (a:'a, b:'b) = call_2 (a, b) 101 | call (Unchecked.defaultof , value) 102 | 103 | type MapItem4 = 104 | static member MapItem4 ((a, b, c, d, e), fn) = (a, b, c, fn d, e) 105 | static member MapItem4 ((a, b, c, d) , fn) = (a, b, c, fn d) 106 | 107 | static member inline Invoke f value = 108 | let inline call_2 (a:^a, b:^b) = ((^a or ^b) : (static member MapItem4: _ * _ -> _) b, f) 109 | let inline call (a:'a, b:'b) = call_2 (a, b) 110 | call (Unchecked.defaultof , value) 111 | 112 | type MapItem5 = 113 | static member MapItem5 ((a, b, c, d, e), fn) = (a, b, c, d, fn e) -------------------------------------------------------------------------------- /FsControl.Test/App.config: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /FsControl.Test/FsControl.Test.fsproj: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 11 6 | FsControl.Test 7 | 8 | 9 | Debug 10 | AnyCPU 11 | 2.0 12 | 070c8382-4bb8-4eaf-a18f-5cd76762e2d2 13 | Library 14 | FsControl.Test 15 | FsControl.Test 16 | true 17 | true 18 | v4.5 19 | 3186 20 | 21 | 22 | 23 | 24 | 4.3.0.0 25 | 26 | 27 | 28 | 29 | 4.3.1.0 30 | 31 | 32 | 33 | 34 | true 35 | full 36 | false 37 | false 38 | bin\Debug\ 39 | DEBUG;TRACE 40 | 3 41 | bin\Debug\FsControl.Test.XML 42 | 43 | 44 | pdbonly 45 | true 46 | true 47 | bin\Release\ 48 | TRACE 49 | 3 50 | bin\Release\FsControl.Test.XML 51 | 52 | 53 | 54 | 55 | $(MSBuildExtensionsPath32)\..\Microsoft SDKs\F#\3.0\Framework\v4.0\Microsoft.FSharp.Targets 56 | 57 | 58 | 59 | 60 | $(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)\FSharp\Microsoft.FSharp.Targets 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | ..\packages\FSharp.Core.3.1.2.5\lib\net40\FSharp.Core.dll 77 | True 78 | 79 | 80 | ..\packages\MathNet.Numerics.3.8.0\lib\net40\MathNet.Numerics.dll 81 | True 82 | 83 | 84 | ..\packages\MathNet.Numerics.FSharp.3.8.0\lib\net40\MathNet.Numerics.FSharp.dll 85 | True 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | FsControl.Core 94 | {92eb1018-06de-4300-8daa-047f4f53c2b9} 95 | True 96 | 97 | 98 | -------------------------------------------------------------------------------- /FsControl.Test/MSTest.runsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | true 5 | 6 | -------------------------------------------------------------------------------- /FsControl.Test/UnitTest.fs: -------------------------------------------------------------------------------- 1 | namespace FsControl.Test 2 | 3 | open System 4 | open Microsoft.VisualStudio.TestTools.UnitTesting 5 | open FsControl.Operators 6 | 7 | type MonadBuilder() = 8 | member inline b.Return(x) = result x 9 | member inline b.Bind(p,rest) = p >>= rest 10 | member b.Let (p,rest) = rest p 11 | member b.ReturnFrom(expr) = expr 12 | 13 | module Combinators = 14 | let inline flip f x y = f y x 15 | let inline konst k _ = k 16 | let inline () x 17 | let inline (/>) x = flip x 18 | let inline choice f g = function Choice2Of2 x -> f x | Choice1Of2 y -> g y 19 | let inline option n f = function None -> n | Some x -> f x 20 | let monad = new MonadBuilder() 21 | open Combinators 22 | 23 | 24 | type WrappedListA<'s> = WrappedListA of 's list with 25 | static member ToSeq (WrappedListA lst) = List.toSeq lst 26 | static member OfSeq lst = WrappedListA (Seq.toList lst) 27 | 28 | type WrappedListB<'s> = WrappedListB of 's list with 29 | static member Return (x) = WrappedListB [x] 30 | static member Append (WrappedListB l, WrappedListB x) = WrappedListB (l @ x) 31 | static member Empty = WrappedListB List.empty 32 | static member ToSeq (WrappedListB lst) = List.toSeq lst 33 | static member FoldBack (WrappedListB x, f, z) = List.foldBack f x z 34 | 35 | type WrappedListC<'s> = WrappedListC of 's list with 36 | static member Append (WrappedListC l, WrappedListC x) = WrappedListC (l @ x) 37 | static member Empty = WrappedListC List.empty 38 | static member Concat (lst: seq>) = Seq.head lst 39 | 40 | type WrappedListD<'s> = WrappedListD of 's list with 41 | interface Collections.Generic.IEnumerable<'s> with member x.GetEnumerator() = (let (WrappedListD x) = x in x :> _ seq).GetEnumerator() 42 | interface Collections.IEnumerable with member x.GetEnumerator() = (let (WrappedListD x) = x in x :> _ seq).GetEnumerator() :> Collections.IEnumerator 43 | static member Return (x) = WrappedListD [x] 44 | static member Bind ((WrappedListD x):WrappedListD<'T>, f) = WrappedListD (List.collect (f >> (fun (WrappedListD x) -> x)) x) 45 | 46 | 47 | [] 48 | type Monoid() = 49 | [] 50 | member x.mconcat_Default_Custom() = 51 | let (WrappedListB x) = concat [WrappedListB [10] ;WrappedListB [15]] 52 | let (WrappedListC y) = concat [WrappedListC [10] ;WrappedListC [15]] 53 | Assert.AreEqual (x, [10;15]) 54 | Assert.AreEqual (y, [10]) 55 | 56 | 57 | [] 58 | type Foldable() = 59 | [] 60 | member x.filter_Default_Custom() = 61 | let wlA1 = WrappedListA [1..10] 62 | let testVal = filter ((=)2) wlA1 63 | Assert.AreEqual (testVal, WrappedListA [2]) 64 | Assert.IsInstanceOfType(Some testVal, typeof>>) 65 | 66 | 67 | [] 68 | member x.FromToSeq() = 69 | let s = (seq [Collections.Generic.KeyValuePair(1, "One"); Collections.Generic.KeyValuePair(2, "Two")]) 70 | let t = {'a'..'d'} 71 | 72 | let dc2:Collections.Generic.Dictionary<_,_> = ofSeq s 73 | let s' = toSeq dc2 74 | 75 | let arr:_ [] = ofSeq s 76 | let s'' = toSeq arr 77 | 78 | let str:string = ofSeq t 79 | let t' = toSeq str 80 | 81 | Assert.AreEqual (toList s, toList s') 82 | Assert.AreEqual (toList s , toList s'') 83 | Assert.AreEqual (toList t , toList t') 84 | 85 | Assert.IsInstanceOfType(Some s, (Some s').GetType()) 86 | Assert.IsInstanceOfType(Some s, (Some s'').GetType()) 87 | Assert.IsInstanceOfType(Some t, (Some t' ).GetType()) 88 | 89 | 90 | [] 91 | member x.SortBy() = 92 | let l = [10;4;6;89] 93 | let l' = sortBy id l 94 | let s = WrappedListB [10;4;6;89] 95 | let s' = sortBy id s 96 | Assert.AreEqual (l', [4;6;10;89]) 97 | Assert.AreEqual (s', WrappedListB [4;6;10;89]) 98 | 99 | 100 | [] 101 | type Monad() = 102 | [] 103 | member x.WorkFlow() = 104 | let testVal = 105 | monad { 106 | let! x1 = WrappedListD [1;2] 107 | let! x2 = WrappedListD [10;20] 108 | return ((+) x1 x2) } 109 | Assert.IsInstanceOfType (testVal, typeof>) 110 | 111 | 112 | 113 | [] 114 | type Traversable() = 115 | [] 116 | member x.sequenceA_Default_Primitive() = 117 | let testVal = sequenceA [|Some 1; Some 2|] 118 | Assert.AreEqual (Some [|1;2|], testVal) 119 | Assert.IsInstanceOfType (testVal, typeof>>) 120 | 121 | member x.sequenceA_Specialization() = 122 | let inline seqSeq (x:_ seq ) = sequenceA x 123 | let inline seqArr (x:_ [] ) = sequenceA x 124 | let inline seqLst (x:_ list) = sequenceA x 125 | 126 | let a = seqSeq (seq [[1];[3]]) 127 | Assert.AreEqual ([seq [1; 3]], a) 128 | Assert.IsInstanceOfType (a, typeof>>) 129 | let b = seqArr ( [|[1];[3]|]) 130 | Assert.AreEqual ([[|1; 3|]], b) 131 | Assert.IsInstanceOfType (b, typeof>>) 132 | let c = seqLst ( [ [1];[3] ]) 133 | Assert.AreEqual ([[1; 3]], c) 134 | Assert.IsInstanceOfType (c, typeof>>) 135 | 136 | 137 | type ZipList<'s> = ZipList of 's seq with 138 | static member Map (ZipList x, f:'a->'b) = ZipList (Seq.map f x) 139 | static member Return (x:'a) = ZipList (Seq.initInfinite (konst x)) 140 | static member (<*>) (ZipList (f:seq<'a->'b>), ZipList x) = ZipList (Seq.zip f x |> Seq.map (fun (f, x) -> f x)) :ZipList<'b> 141 | 142 | type ZipList'<'s> = ZipList' of 's seq with 143 | static member Return (x:'a) = ZipList' (Seq.initInfinite (konst x)) 144 | static member (<*>) (ZipList' (f:seq<'a->'b>), ZipList' x) = ZipList' (Seq.zip f x |> Seq.map (fun (f, x) -> f x)) :ZipList'<'b> 145 | 146 | [] 147 | type Applicative() = 148 | [] 149 | member x.ApplicativeMath() = 150 | let inline (+) (a:'T) (b:'T) :'T = a + b 151 | let inline ( |+ ) (x :'Functor't) (y :'t) = map ((+)/> y) x :'Functor't 152 | let inline ( +| ) (x :'t) (y :'Functor't) = map ((+) x) y :'Functor't 153 | let inline ( |+| ) (x :'Applicative't) (y :'Applicative't) = (+) x <*> y :'Applicative't 154 | 155 | let testVal = [1;2] |+| [10;20] |+| [100;200] |+ 2 156 | Assert.AreEqual ([113; 213; 123; 223; 114; 214; 124; 224], testVal) 157 | Assert.IsInstanceOfType (Some testVal, typeof>>) 158 | 159 | 160 | [] 161 | member x.Applicatives() = 162 | 163 | let run (ZipList x) = x 164 | let run' (ZipList' x) = x 165 | 166 | // Test Applicative (functions) 167 | let res607 = map (+) ( (*) 100 ) 6 7 168 | let res606 = ( (+) <*> (*) 100 ) 6 169 | let res508 = (map (+) ((+) 3 ) <*> (*) 100) 5 170 | 171 | // Test Applicative (ZipList) 172 | let res9n5 = map ((+) 1) (ZipList [8;4]) 173 | let res20n30 = result (+) <*> result 10 <*> ZipList [10;20] 174 | let res18n14 = result (+) <*> ZipList [8;4] <*> result 10 175 | let res9n5' = map ((+) 1) (ZipList' [8;4]) 176 | 177 | Assert.AreEqual (607, res607) 178 | Assert.AreEqual (606, res606) 179 | Assert.AreEqual (508, res508) 180 | Assert.AreEqual (toList (run res9n5), toList (run' res9n5')) 181 | 182 | 183 | // Idiom brackets from http://www.haskell.org/haskellwiki/Idiom_brackets 184 | type Ii = Ii 185 | type Ji = Ji 186 | type J = J 187 | type Idiomatic = Idiomatic with 188 | static member inline ($) (Idiomatic, si) = fun sfi x -> (Idiomatic $ x) (sfi <*> si) 189 | static member ($) (Idiomatic, Ii) = id 190 | 191 | type Applicative with 192 | [] 193 | member x.IdiomBrackets() = 194 | let inline idiomatic a b = (Idiomatic $ b) a 195 | let inline iI x = (idiomatic << result) x 196 | 197 | let res3n4'' = iI ((+) 2) [1;2] Ii 198 | let res3n4''' = iI (+) (result 2) [1;2] Ii // fails to compile when constraints are not properly defined 199 | Assert.AreEqual ([3;4], res3n4'' ) 200 | Assert.AreEqual ([3;4], res3n4''') 201 | 202 | 203 | 204 | 205 | let output = System.Text.StringBuilder() 206 | let append (x:string) = output.Append x |> ignore 207 | 208 | let v5: Lazy<_> = lazy (append "5"; 5) 209 | Assert.AreEqual (0, output.Length) 210 | let fPlus10 x = lazy (append " + 10"; x + 10) 211 | Assert.AreEqual (0, output.Length) 212 | let v5plus10 = v5 >>= fPlus10 213 | Assert.AreEqual (0, output.Length) 214 | let v15 = v5plus10.Force() 215 | Assert.AreEqual ("5 + 10", output.ToString()) 216 | Assert.AreEqual (15, v15) 217 | 218 | output.Clear() |> ignore 219 | 220 | let v4ll: Lazy<_> = lazy (append "outer"; lazy (append "inner"; 4)) 221 | Assert.AreEqual (0, output.Length) 222 | let v4l = join v4ll 223 | Assert.AreEqual (0, output.Length) 224 | let v4 = v4l.Force() 225 | Assert.AreEqual ("outerinner", output.ToString()) 226 | Assert.AreEqual (4, v4) 227 | 228 | 229 | module NumericLiteralG = 230 | open FsControl 231 | let inline FromZero() = Zero.Invoke() 232 | let inline FromOne () = One.Invoke() 233 | let inline FromInt32 (i:int ) = FromInt32.Invoke i 234 | let inline FromInt64 (i:int64 ) = FromInt64.Invoke i 235 | let inline FromString (i:string) = fromBigInt <| System.Numerics.BigInteger.Parse i 236 | 237 | open MathNet.Numerics 238 | 239 | [] 240 | type Numerics() = 241 | [] 242 | member x.GenericMath() = 243 | let argUint :uint32 = 42G 244 | let argInt : int = -424242G 245 | let argBigInt : bigint = -42424242424242G 246 | let argFloat : float = -(42G + (42G/100G)) // -42.42 247 | let argFloat32 : float32 = -(42G + (42G/100G)) // -42.4199982f 248 | let argDecimal : decimal = -(42G + (42G/100G)) 249 | let argComplex = Complex.mkRect(-42.42, 24.24) 250 | let argComplex32 = Complex32.mkRect(-42.42f, 24.24f) 251 | let argBigRational : BigRational = -42424242424242G / 42424G 252 | 253 | let res01 = signum' argUint 254 | let res02 = signum' argInt 255 | let res03 = signum' argBigInt 256 | let res04 = signum' argFloat 257 | let res05 = signum' argFloat32 258 | let res06 = signum' argDecimal 259 | let res07 = signum' argComplex 260 | let res08 = signum' argComplex32 261 | let res09 = signum' argBigRational 262 | 263 | let res11 = abs' argUint 264 | let res12 = abs' argInt 265 | let res13 = abs' argBigInt 266 | let res14 = abs' argFloat 267 | let res15 = abs' argFloat32 268 | let res16 = abs' argDecimal 269 | let res17 = abs' argComplex 270 | let res18 = abs' argComplex32 271 | let res19 = abs' argBigRational 272 | 273 | Assert.AreEqual(res09 * res19, argBigRational) 274 | 275 | 276 | type Sum<'a> = Sum of 'a with 277 | static member inline get_Empty() = Sum 0G 278 | static member inline Append (Sum (x:'n), Sum(y:'n)) = Sum (x + y) 279 | 280 | 281 | [] 282 | type Splits() = 283 | [] 284 | member x.SplitArraysAndStrings() = 285 | let a1 = "this.isABa.tABCest" |> split [|"AT" ; "ABC" |] 286 | let a2 = "this.isABa.tABCest"B |> split [|"AT"B; "ABC"B|] |> Seq.map System.Text.Encoding.ASCII.GetString 287 | 288 | let b1 = "this.is.a.t...est" |> split [|"." ; "..." |] 289 | let b2 = "this.is.a.t...est"B |> split [|"."B; "..."B|] |> Seq.map System.Text.Encoding.ASCII.GetString 290 | 291 | Assert.IsTrue((toList a1 = toList a2)) 292 | Assert.IsTrue((toList b1 = toList b2)) 293 | 294 | member x.ReplaceArraysAndStrings() = 295 | let a1 = "this.isABa.tABCest" |> replace "AT" "ABC" 296 | let a2 = "this.isABa.tABCest"B |> replace "AT"B "ABC"B |> System.Text.Encoding.ASCII.GetString 297 | 298 | let b1 = "this.is.a.t...est" |> replace "." "..." 299 | let b2 = "this.is.a.t...est"B |> replace "."B "..."B |> System.Text.Encoding.ASCII.GetString 300 | 301 | Assert.IsTrue((a1 = a2)) 302 | Assert.IsTrue((b1 = b2)) 303 | 304 | member x.IntercalateArraysAndStrings() = 305 | let a1 = [|"this" ; "is" ; "a" ; "test" |] |> intercalate " " 306 | let a2 = [|"this"B; "is"B; "a"B; "test"B|] |> intercalate " "B |> System.Text.Encoding.ASCII.GetString 307 | 308 | let b = [WrappedListB [1;2]; WrappedListB [3;4]; WrappedListB [6;7]] |> intercalate (WrappedListB [0;1]) 309 | 310 | // Fails to compile but works in F#4.1 311 | // let c = [| Sum 1; Sum 2 |] |> intercalate (Sum 10) 312 | // 313 | 314 | let d = WrappedListB [Sum 1; Sum 2] |> intercalate (Sum 10) 315 | 316 | Assert.IsTrue((a1 = a2)) 317 | Assert.IsTrue((b = WrappedListB [1; 2; 0; 1; 3; 4; 0; 1; 6; 7])) 318 | // Assert.IsTrue((c = Sum 13)) 319 | Assert.IsTrue((d = Sum 13)) -------------------------------------------------------------------------------- /FsControl.Test/packages.config: -------------------------------------------------------------------------------- 1 |  2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /FsControl.sln: -------------------------------------------------------------------------------- 1 |  2 | Microsoft Visual Studio Solution File, Format Version 12.00 3 | # Visual Studio 14 4 | VisualStudioVersion = 14.0.23107.0 5 | MinimumVisualStudioVersion = 10.0.40219.1 6 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsControl.Core", "FsControl.Core\FsControl.Core.fsproj", "{92EB1018-06DE-4300-8DAA-047F4F53C2B9}" 7 | EndProject 8 | Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FsControl.BaseLib", "FsControl.BaseLib\FsControl.BaseLib.csproj", "{1B99DF98-65AC-4038-8BE5-E72B0882F420}" 9 | EndProject 10 | Project("{F2A71F9B-5D33-465A-A702-920D77279786}") = "FsControl.Test", "FsControl.Test\FsControl.Test.fsproj", "{070C8382-4BB8-4EAF-A18F-5CD76762E2D2}" 11 | EndProject 12 | Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = ".nuget", ".nuget", "{7172832B-0AD3-4109-AAF0-F9E15E0073B3}" 13 | ProjectSection(SolutionItems) = preProject 14 | .nuget\packages.config = .nuget\packages.config 15 | EndProjectSection 16 | EndProject 17 | Global 18 | GlobalSection(SolutionConfigurationPlatforms) = preSolution 19 | Debug|Any CPU = Debug|Any CPU 20 | Release|Any CPU = Release|Any CPU 21 | EndGlobalSection 22 | GlobalSection(ProjectConfigurationPlatforms) = postSolution 23 | {92EB1018-06DE-4300-8DAA-047F4F53C2B9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 24 | {92EB1018-06DE-4300-8DAA-047F4F53C2B9}.Debug|Any CPU.Build.0 = Debug|Any CPU 25 | {92EB1018-06DE-4300-8DAA-047F4F53C2B9}.Release|Any CPU.ActiveCfg = Release|Any CPU 26 | {92EB1018-06DE-4300-8DAA-047F4F53C2B9}.Release|Any CPU.Build.0 = Release|Any CPU 27 | {1B99DF98-65AC-4038-8BE5-E72B0882F420}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 28 | {1B99DF98-65AC-4038-8BE5-E72B0882F420}.Debug|Any CPU.Build.0 = Debug|Any CPU 29 | {1B99DF98-65AC-4038-8BE5-E72B0882F420}.Release|Any CPU.ActiveCfg = Release|Any CPU 30 | {1B99DF98-65AC-4038-8BE5-E72B0882F420}.Release|Any CPU.Build.0 = Release|Any CPU 31 | {070C8382-4BB8-4EAF-A18F-5CD76762E2D2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU 32 | {070C8382-4BB8-4EAF-A18F-5CD76762E2D2}.Debug|Any CPU.Build.0 = Debug|Any CPU 33 | {070C8382-4BB8-4EAF-A18F-5CD76762E2D2}.Release|Any CPU.ActiveCfg = Release|Any CPU 34 | {070C8382-4BB8-4EAF-A18F-5CD76762E2D2}.Release|Any CPU.Build.0 = Release|Any CPU 35 | EndGlobalSection 36 | GlobalSection(SolutionProperties) = preSolution 37 | HideSolutionNode = FALSE 38 | EndGlobalSection 39 | EndGlobal 40 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Apache License 2 | Version 2.0, January 2004 3 | http://www.apache.org/licenses/ 4 | 5 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 6 | 7 | 1. Definitions. 8 | 9 | "License" shall mean the terms and conditions for use, reproduction, 10 | and distribution as defined by Sections 1 through 9 of this document. 11 | 12 | "Licensor" shall mean the copyright owner or entity authorized by 13 | the copyright owner that is granting the License. 14 | 15 | "Legal Entity" shall mean the union of the acting entity and all 16 | other entities that control, are controlled by, or are under common 17 | control with that entity. For the purposes of this definition, 18 | "control" means (i) the power, direct or indirect, to cause the 19 | direction or management of such entity, whether by contract or 20 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 21 | outstanding shares, or (iii) beneficial ownership of such entity. 22 | 23 | "You" (or "Your") shall mean an individual or Legal Entity 24 | exercising permissions granted by this License. 25 | 26 | "Source" form shall mean the preferred form for making modifications, 27 | including but not limited to software source code, documentation 28 | source, and configuration files. 29 | 30 | "Object" form shall mean any form resulting from mechanical 31 | transformation or translation of a Source form, including but 32 | not limited to compiled object code, generated documentation, 33 | and conversions to other media types. 34 | 35 | "Work" shall mean the work of authorship, whether in Source or 36 | Object form, made available under the License, as indicated by a 37 | copyright notice that is included in or attached to the work 38 | (an example is provided in the Appendix below). 39 | 40 | "Derivative Works" shall mean any work, whether in Source or Object 41 | form, that is based on (or derived from) the Work and for which the 42 | editorial revisions, annotations, elaborations, or other modifications 43 | represent, as a whole, an original work of authorship. For the purposes 44 | of this License, Derivative Works shall not include works that remain 45 | separable from, or merely link (or bind by name) to the interfaces of, 46 | the Work and Derivative Works thereof. 47 | 48 | "Contribution" shall mean any work of authorship, including 49 | the original version of the Work and any modifications or additions 50 | to that Work or Derivative Works thereof, that is intentionally 51 | submitted to Licensor for inclusion in the Work by the copyright owner 52 | or by an individual or Legal Entity authorized to submit on behalf of 53 | the copyright owner. For the purposes of this definition, "submitted" 54 | means any form of electronic, verbal, or written communication sent 55 | to the Licensor or its representatives, including but not limited to 56 | communication on electronic mailing lists, source code control systems, 57 | and issue tracking systems that are managed by, or on behalf of, the 58 | Licensor for the purpose of discussing and improving the Work, but 59 | excluding communication that is conspicuously marked or otherwise 60 | designated in writing by the copyright owner as "Not a Contribution." 61 | 62 | "Contributor" shall mean Licensor and any individual or Legal Entity 63 | on behalf of whom a Contribution has been received by Licensor and 64 | subsequently incorporated within the Work. 65 | 66 | 2. Grant of Copyright License. Subject to the terms and conditions of 67 | this License, each Contributor hereby grants to You a perpetual, 68 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 69 | copyright license to reproduce, prepare Derivative Works of, 70 | publicly display, publicly perform, sublicense, and distribute the 71 | Work and such Derivative Works in Source or Object form. 72 | 73 | 3. Grant of Patent License. Subject to the terms and conditions of 74 | this License, each Contributor hereby grants to You a perpetual, 75 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 76 | (except as stated in this section) patent license to make, have made, 77 | use, offer to sell, sell, import, and otherwise transfer the Work, 78 | where such license applies only to those patent claims licensable 79 | by such Contributor that are necessarily infringed by their 80 | Contribution(s) alone or by combination of their Contribution(s) 81 | with the Work to which such Contribution(s) was submitted. If You 82 | institute patent litigation against any entity (including a 83 | cross-claim or counterclaim in a lawsuit) alleging that the Work 84 | or a Contribution incorporated within the Work constitutes direct 85 | or contributory patent infringement, then any patent licenses 86 | granted to You under this License for that Work shall terminate 87 | as of the date such litigation is filed. 88 | 89 | 4. Redistribution. You may reproduce and distribute copies of the 90 | Work or Derivative Works thereof in any medium, with or without 91 | modifications, and in Source or Object form, provided that You 92 | meet the following conditions: 93 | 94 | (a) You must give any other recipients of the Work or 95 | Derivative Works a copy of this License; and 96 | 97 | (b) You must cause any modified files to carry prominent notices 98 | stating that You changed the files; and 99 | 100 | (c) You must retain, in the Source form of any Derivative Works 101 | that You distribute, all copyright, patent, trademark, and 102 | attribution notices from the Source form of the Work, 103 | excluding those notices that do not pertain to any part of 104 | the Derivative Works; and 105 | 106 | (d) If the Work includes a "NOTICE" text file as part of its 107 | distribution, then any Derivative Works that You distribute must 108 | include a readable copy of the attribution notices contained 109 | within such NOTICE file, excluding those notices that do not 110 | pertain to any part of the Derivative Works, in at least one 111 | of the following places: within a NOTICE text file distributed 112 | as part of the Derivative Works; within the Source form or 113 | documentation, if provided along with the Derivative Works; or, 114 | within a display generated by the Derivative Works, if and 115 | wherever such third-party notices normally appear. The contents 116 | of the NOTICE file are for informational purposes only and 117 | do not modify the License. You may add Your own attribution 118 | notices within Derivative Works that You distribute, alongside 119 | or as an addendum to the NOTICE text from the Work, provided 120 | that such additional attribution notices cannot be construed 121 | as modifying the License. 122 | 123 | You may add Your own copyright statement to Your modifications and 124 | may provide additional or different license terms and conditions 125 | for use, reproduction, or distribution of Your modifications, or 126 | for any such Derivative Works as a whole, provided Your use, 127 | reproduction, and distribution of the Work otherwise complies with 128 | the conditions stated in this License. 129 | 130 | 5. Submission of Contributions. Unless You explicitly state otherwise, 131 | any Contribution intentionally submitted for inclusion in the Work 132 | by You to the Licensor shall be under the terms and conditions of 133 | this License, without any additional terms or conditions. 134 | Notwithstanding the above, nothing herein shall supersede or modify 135 | the terms of any separate license agreement you may have executed 136 | with Licensor regarding such Contributions. 137 | 138 | 6. Trademarks. This License does not grant permission to use the trade 139 | names, trademarks, service marks, or product names of the Licensor, 140 | except as required for reasonable and customary use in describing the 141 | origin of the Work and reproducing the content of the NOTICE file. 142 | 143 | 7. Disclaimer of Warranty. Unless required by applicable law or 144 | agreed to in writing, Licensor provides the Work (and each 145 | Contributor provides its Contributions) on an "AS IS" BASIS, 146 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 147 | implied, including, without limitation, any warranties or conditions 148 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 149 | PARTICULAR PURPOSE. You are solely responsible for determining the 150 | appropriateness of using or redistributing the Work and assume any 151 | risks associated with Your exercise of permissions under this License. 152 | 153 | 8. Limitation of Liability. In no event and under no legal theory, 154 | whether in tort (including negligence), contract, or otherwise, 155 | unless required by applicable law (such as deliberate and grossly 156 | negligent acts) or agreed to in writing, shall any Contributor be 157 | liable to You for damages, including any direct, indirect, special, 158 | incidental, or consequential damages of any character arising as a 159 | result of this License or out of the use or inability to use the 160 | Work (including but not limited to damages for loss of goodwill, 161 | work stoppage, computer failure or malfunction, or any and all 162 | other commercial damages or losses), even if such Contributor 163 | has been advised of the possibility of such damages. 164 | 165 | 9. Accepting Warranty or Additional Liability. While redistributing 166 | the Work or Derivative Works thereof, You may choose to offer, 167 | and charge a fee for, acceptance of support, warranty, indemnity, 168 | or other liability obligations and/or rights consistent with this 169 | License. However, in accepting such obligations, You may act only 170 | on Your own behalf and on Your sole responsibility, not on behalf 171 | of any other Contributor, and only if You agree to indemnify, 172 | defend, and hold each Contributor harmless for any liability 173 | incurred by, or claims asserted against, such Contributor by reason 174 | of your accepting any such warranty or additional liability. 175 | 176 | END OF TERMS AND CONDITIONS 177 | 178 | APPENDIX: How to apply the Apache License to your work. 179 | 180 | To apply the Apache License to your work, attach the following 181 | boilerplate notice, with the fields enclosed by brackets "{}" 182 | replaced with your own identifying information. (Don't include 183 | the brackets!) The text should be enclosed in the appropriate 184 | comment syntax for the file format. We also recommend that a 185 | file or class name and description of purpose be included on the 186 | same "printed page" as the copyright notice for easier 187 | identification within third-party archives. 188 | 189 | Copyright {yyyy} {name of copyright owner} 190 | 191 | Licensed under the Apache License, Version 2.0 (the "License"); 192 | you may not use this file except in compliance with the License. 193 | You may obtain a copy of the License at 194 | 195 | http://www.apache.org/licenses/LICENSE-2.0 196 | 197 | Unless required by applicable law or agreed to in writing, software 198 | distributed under the License is distributed on an "AS IS" BASIS, 199 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 200 | See the License for the specific language governing permissions and 201 | limitations under the License. 202 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FsControl [![Build Status](https://api.travis-ci.org/gmpl/FsControl.svg?branch=master)](https://travis-ci.org/gmpl/FsControl) 2 | ========= 3 | 4 | A library that enhances the F# coding experience by providing the following two innovations: 5 | 6 | 1. A mechanism for defining standalone generic functions within F# similar to Haskell's typeclasses (once their defining module is in scope). These generic functions are resolved at compile time to an implementation type using .Net's static class method overloading mechanism, .Net type extension facility, and F#'s type inferencing. For example, a generic definition of Map may be made so as to automatically resolve to List.map, Array.map, Seq.map, or whatever the provided mappable (Functor) value's implementation of Map resolves to at compile time. 7 | 8 | 2. The provision of a set of generic standalone function definitions together with their implementation over a set of .NET and F# core types. Some of these functions are abstractions ported from Haskell but adapted to the F#/.NET world. Other functions offer a solution to normalize common function calls over different Types which represent the same abstraction but mainly due to historical reasons have different names and signatures. 9 | 10 | 11 | 12 | 13 | ### NOTE: FsControl is part of [FSharpPlus](https://github.com/gmpl/FSharpPlus) now. 14 | 15 | ### This project is no longer maintained here. 16 | 17 | 18 | 19 | 20 | 21 | ### Getting Started 22 | 23 | 24 | - Download binaries from [Nuget](https://www.nuget.org/packages/FsControl/), use the latest version (2.x) 25 | 26 | - Open an F# script file or the F# interactive and reference the library 27 | ```fsharp 28 | #r @"C:\Your path to the binaries\FsControl.dll";; 29 | ``` 30 | Ignore warnings about F# metadata. 31 | 32 | - Now you can create generic functions, here's an example with map ([fmap](https://wiki.haskell.org/Functor) for Haskellers, [Select](http://www.dotnetperls.com/select) for C-sharpers): 33 | ```fsharp 34 | let inline map f x = FsControl.Map.Invoke f x;; 35 | ``` 36 | Static constraints will be inferred automatically. 37 | 38 | - Test it with .NET / F# primitive types: 39 | ```fsharp 40 | map string [|2;3;4;5|];; 41 | // val it : string [] = [|"2"; "3"; "4"; "5"|] 42 | 43 | map ((+) 9) (Some 3);; 44 | // val it : int option = Some 12 45 | ``` 46 | - You can also create your own type with a method Map: 47 | ```fsharp 48 | type Tree<'t> = 49 | | Tree of 't * Tree<'t> * Tree<'t> 50 | | Leaf of 't 51 | static member Map (x:Tree<'a>, f) = 52 | let rec loop f = function 53 | | Leaf x -> Leaf (f x) 54 | | Tree (x, t1, t2) -> Tree (f x, loop f t1, loop f t2) 55 | loop f x 56 | ``` 57 | By adding the static member Map we say that we're making Tree an instance of Map. 58 | 59 | - Try mapping over your new type: 60 | ```fsharp 61 | let myTree = Tree(6, Tree(2, Leaf 1, Leaf 3), Leaf 9);; 62 | map ((*) 10) myTree;; 63 | // val it : Tree = Tree (60,Tree (20,Leaf 10,Leaf 30),Leaf 90) 64 | ``` 65 | Generic functions may be seen as an exotic thing in F# that only saves a few key strokes (map instead of List.map or Array.map) still they allow you to reach a higher abstraction level, using ad-hoc polymorphism. 66 | 67 | But more interesting is the use of operators. You can't prefix them with the module they belong to, well you can but then it's no longer an operator. As an example many F# libraries define the bind operator (>>=) but it's not generic so if you use two different types which are both monads you will need to prefix it e.g. State.(>>=) and Reader.(>>=) which defeats the purpose of having an operator. 68 | 69 | Here you can easily define a generic bind operator: 70 | ```fsharp 71 | let inline (>>=) x f = Bind.Invoke x f 72 | ``` 73 | Or if you do [Railway Oriented Programming](https://www.google.ch/#q=railway+oriented+programming) you can finally have your generic Kleisli composition (fish) operator: 74 | ```fsharp 75 | let inline (>=>) f g x = Bind.Invoke (f x) g 76 | ``` 77 | Also when working with combinators, the generic applicative functor (space invaders) operator is very handy: 78 | ```fsharp 79 | let inline (<*>) x y = Apply.Invoke x y 80 | ``` 81 | Of course they are already defined in the FsControl.Operators module and they work with primitive and user defined types. 82 | 83 | 84 | ### Next steps: 85 | - Have a look at the [sample files](https://github.com/gmpl/FsControl/blob/master/FsControl.Core/Samples/) adjust the path of the binaries and run the .fsx scripts. 86 | - Before creating your own library of generic functions be aware that [FsControl.Operators](https://github.com/gmpl/FsControl/blob/master/FsControl.Core/Operators.fs) is a lightweight module with some operators and functions used mainly to test the project. Also take the time to visit [F#+](https://github.com/gmpl/FSharpPlus) which is a library that re-export all those functions and also provides more derived operators, builders and other interesting stuff. 87 | - In the rare case that you are not interested in the generic stuff but want to re-use specific implementations many methods in FsControl are defined as extension methods and some have a C# friendly signature. 88 | - Keep reading the doc. 89 | 90 | How does it works 91 | ----------------- 92 | 93 | Technically this is a base library with a collection of generic methods overloaded for .NET and F# core types but extensible to other types at the same time. 94 | 95 | There are basically two Types involved in these overloads: 96 | 97 | - The type that will implement the abstraction. This will be a “real” type, for example List or Tree. We may refer to this type as the type or as the instance-type, since it represents an instance of the abstraction. At the same time we can classify these types in primitive types and custom types. By primitive types we refer to existing types in the .NET framework. 98 | 99 | - The type that represent the abstraction: Examples of these types are Map, Bind, Append, etc. This will be a "dummy" type implemented as a static class with an overloaded method (usually with the same name as the type) and an entry point method called 'Invoke'. From now on and in order to differentiate from the type-instance we will call this type the method-class. 100 | 101 | For Haskellers this 'method-class' abstraction is similar to Haskell's Type-Classes but with a single method. 102 | 103 | For OOP-ers it may compare to interfaces or abstract classes but with a single method, early binding (compile-time) and without dependencies on the assembly where the interface is defined. 104 | 105 | FsControl contains overloads mainly for primitive types, but the generic functions will resolve to any type (a user-defined type) having a member with a matching signature. This makes possible to use some libraries that don't depend on FsControl, as long as the signature is the right one it will work. 106 | 107 | 108 | 109 | How to use FsControl 110 | -------------------- 111 | 112 | You may find hard to understand how to use FsControl, the best is to have a look at the source code, if you just want to use the generic functions for primitive types open FsControl.Operators module. 113 | 114 | 115 | The purpose of the overloads is to associate primitive types with method-classes, here we can have three different scenarios: 116 | 117 | 1) Add a new method-class and instance-types for existing types. 118 | 119 | This is the most complex scenario, to define a new method-class is not straightforward, there will be some guidelines but at the moment the best is to have a look at the source code. 120 | 121 | 2) Add a new type and make it an instance of an existing method-class. 122 | 123 | There are 2 ways: 124 | 125 | a) You can have a look at the signature of the method you want to implement in the source code, which will follow this convention: 126 | ```fsharp 127 | static member [inline] [MethodName] (arg1:Type, [more args], output[:ReturnType], mthd[:MethodClassName]) = 128 | Implementation 129 | ``` 130 | To find the exact signature you need to look at the source code of the method-class you are interested. 131 | 132 | Here's an example: 133 | 134 | In the source code for Map (in Functor.fs) the option instance is defined like this: 135 | ```fsharp 136 | []static member Map (x:option<_>, f, []impl:Map) = Option.map f x 137 | ``` 138 | So you can create a type Tree and add an instance for the existing method-class Map this way: 139 | ```fsharp 140 | // Define a type Tree 141 | type Tree<'a> = 142 | | Tree of 'a * Tree<'a> * Tree<'a> 143 | | Leaf of 'a 144 | 145 | // add an instance for Map (Functor) 146 | static member Map (x:Tree<_>, f, impl) = 147 | let rec loop f (t:Tree<'a>) = 148 | match t with 149 | | Leaf x -> Leaf (f x) 150 | | Tree (x, t1, t2) -> Tree (f x, loop f t1, loop f t2) 151 | loop f x 152 | ``` 153 | b) Some methods accept also a 'clean signature' without the unused parameters output and impl. You can find a list of these methods below, in the section "How can I make my classes FsControl-ready?". This way it doesn't require to reference FsControl binaries. 154 | 155 | 3) Add an instance for an existing Type of an existing method-class: 156 | 157 | We can’t do this. This is only possible if we have control over the source code of either the instance-type or the method-class. 158 | The fact that the association must be done either in the instance-class or in the method-class is due to both a technical limitation (1) and a conceptual reason (2). 159 | 160 | - (1) Extensions methods are not taken into account in overload resolution. 161 | - (2) It may lead to a bad design practice, something similar happens in Haskell with Type Classes (see [orphan instances](http://www.haskell.org/haskellwiki/Orphan_instance)). 162 | 163 | Anyway if you find a situation like this you can either wrap the type you're interested in or "shadow" the generic function. 164 | 165 | 166 | How can I make my classes FsControl-ready? 167 | ------------------------------------------ 168 | 169 | An easy way to make classes in your project callable from FsControl without referencing FsControl DLLs at all is to use standard signatures for your methods. Here's a list of the standard signatures available at the moment, this list is not exhaustive: 170 | 171 | Functors: 172 | ```fsharp 173 | static member Map (x:MyFunctor<'T>, f:'T->'U) : MyFunctor<'U> = {my map impl.} 174 | ``` 175 | Applicatives: 176 | ```fsharp 177 | static member Return (x:'T) : MyApplicative<'T> = {my Return impl.} 178 | static member (<*>) (f:MyApplicative<'T->'U>, x:MyApplicative<'T>) : MyApplicative<'U> = {my Apply impl.} 179 | ``` 180 | Monads: 181 | ```fsharp 182 | static member Return (x:'T) : MyMonad<'T> = {my Return impl.} // similar to Applicatives 183 | static member Bind (x:MyMonad<'T>, f:'T->MyMonad<'U>) : MyMonad<'U> = {my Bind impl.} 184 | ``` 185 | Monoids: 186 | ```fsharp 187 | static member Empty : MyMonoid = {my Empty impl.} // get_Empty() = ... may be used alternatively. 188 | static member Append (x:MyMonoid, y:MyMonoid) : MyMonoid = {my Append impl.} 189 | static member Concat (x:seq) : MyMonoid = {my Concat impl.} // optional: it can be automatically derived from Append 190 | ``` 191 | Foldables: 192 | ```fsharp 193 | static member FoldBack (source:MyFoldable<'T>, folder:'T->'State->'State, state:'State) : 'State = {my FoldBack impl.} 194 | static member ToSeq (source:MyFoldable<'T>) : seq<'T> = {my ToSeq impl.} 195 | static member FromSeq (source: seq<'T>) : MyFoldable<'T> = {my FromSeq impl.} 196 | ``` 197 | 198 | If you find problems (typically insane compile times) you can still define it as described in 2). 199 | 200 | FAQ 201 | --- 202 | 203 | Q: Is there a performance penalty in using this library? 204 | 205 | A: Normally not, because all these constraints are resolved at compile time and code is inlined so on the contrary there might be eventually some speed up at run-time. On the other hand, the more overloads the more pressure on the compiler, this project will take several minutes to compile but this doesn't mean that by linking the FsControl dll to an application the compile time of the application will slow down. It will slow down depending on how much generic code (inlined) uses. 206 | 207 | Q: What about the generic abstractions? Do they mean that by having a generic solution the code will be less efficient? 208 | 209 | A: In many cases yes, but in FsControl the most generic code is in 'default methods' and normally the overloads define specialized methods which are optimized for specific instances. 210 | 211 | Q: Where can I find more information about the abstractions provided? 212 | 213 | A: There are many posts on Haskell everywhere, of those some are very formal and others are more intuitive. Apart from that in the last years there were some F# intuitive explanations in different blogs about the same abstractions implemented in F# in a non-generic way. 214 | 215 | Q: Is this a Haskell emulator? 216 | 217 | A: No, there are some abstractions specifics to F#, however it's true that this library (as many others F# libs) is heavily inspired in concepts coming from Haskell but as F# is another language with another type system, strict evaluation and some different conventions there are many differences in names, types and implementations. Also there are some specific F# abstractions. Anyway by knowing those differences you may be able to translate Haskell code to F#. There is a [Haskell Compatibility module in F#+](https://github.com/gmpl/FSharpPlus/blob/master/FSharpPlus/Compatibility.fs#L4) which is another project based in FsControl, and it contains binds to mimic Haskell functions, operator and types. 218 | 219 | Q: How can I contribute to this library? 220 | 221 | A: You can review the code, find better implementations of specific instances, add missing instances for primitive types, add/propose new method-classes, add sample files an so on. Finding issues, making suggestions, giving feedback, discussion in general is also welcome. 222 | -------------------------------------------------------------------------------- /build.fsx: -------------------------------------------------------------------------------- 1 | #if run_with_bin_sh 2 | # See why this works at http://stackoverflow.com/a/21948918/637783 3 | exec fsharpi --define:mono_posix --exec $0 $* 4 | #endif 5 | 6 | (* 7 | * Crossplatform FSharp Makefile Bootstrapper 8 | * Apache licensed - Copyright 2014 Jay Tuley 9 | * v 2.0 https://gist.github.com/jbtule/9243729 10 | * 11 | * How to use: 12 | * On Windows `fsi --exec build.fsx 13 | * 14 | * On Mac Or Linux `./build.fsx ` 15 | * *Note:* But if you have trouble then use `sh build.fsx ` 16 | * 17 | *) 18 | 19 | open System 20 | open System.IO 21 | open System.Diagnostics 22 | 23 | (* helper functions *) 24 | #if mono_posix 25 | #r "Mono.Posix.dll" 26 | open Mono.Unix.Native 27 | let applyExecutionPermissionUnix path = 28 | let _,stat = Syscall.lstat(path) 29 | Syscall.chmod(path, FilePermissions.S_IXUSR ||| stat.st_mode) |> ignore 30 | #else 31 | let applyExecutionPermissionUnix path = () 32 | #endif 33 | 34 | let doesNotExist path = 35 | path |> Path.GetFullPath |> File.Exists |> not 36 | 37 | let execAt (workingDir:string) (exePath:string) (args:string seq) = 38 | let processStart (psi:ProcessStartInfo) = 39 | let ps = Process.Start(psi) 40 | ps.WaitForExit () 41 | ps.ExitCode 42 | let fullExePath = exePath |> Path.GetFullPath 43 | applyExecutionPermissionUnix fullExePath 44 | let exitCode = ProcessStartInfo( 45 | fullExePath, 46 | args |> String.concat " ", 47 | WorkingDirectory = (workingDir |> Path.GetFullPath), 48 | UseShellExecute = false) 49 | |> processStart 50 | if exitCode <> 0 then 51 | exit exitCode 52 | () 53 | 54 | let exec = execAt Environment.CurrentDirectory 55 | 56 | let downloadNugetTo path = 57 | let fullPath = path |> Path.GetFullPath; 58 | if doesNotExist fullPath then 59 | printf "Downloading NuGet..." 60 | use webClient = new System.Net.WebClient() 61 | fullPath |> Path.GetDirectoryName |> Directory.CreateDirectory |> ignore 62 | webClient.DownloadFile("https://nuget.org/nuget.exe", path |> Path.GetFullPath) 63 | printfn "Done." 64 | 65 | let passedArgs = fsi.CommandLineArgs.[1..] |> Array.toList 66 | 67 | (* execution script customize below *) 68 | 69 | let nugetExe = "packages/NuGet/NuGet.exe" 70 | let fakeExe = "packages/FAKE/tools/FAKE.exe" 71 | 72 | downloadNugetTo nugetExe 73 | 74 | if doesNotExist fakeExe then 75 | exec nugetExe ["install"; "FAKE"; "-OutputDirectory packages"; "-ExcludeVersion"; "-Prerelease"] 76 | exec fakeExe ("makefile.fsx"::passedArgs)" -------------------------------------------------------------------------------- /makefile.fsx: -------------------------------------------------------------------------------- 1 | #I @"packages/FAKE/tools/" 2 | #r @"FakeLib.dll" 3 | 4 | open Fake 5 | open System 6 | open System.IO 7 | 8 | let buildDir = "./build" 9 | let nugetDir = "./packages" 10 | let packagesDir = "./packages" 11 | 12 | Target "Clean" (fun _ -> CleanDirs [buildDir]) 13 | 14 | Target "RestorePackages" RestorePackages 15 | 16 | Target "BuildSolution" (fun _ -> 17 | MSBuildWithDefaults "Build" ["./FsControl.Core/FsControl.Core.fsproj"] 18 | |> Log "Core Build-Output: " 19 | MSBuildWithDefaults "Build" ["./FsControl.BaseLib/FsControl.BaseLib.csproj"] 20 | |> Log "BaseLib Build-Output: " 21 | ) 22 | 23 | "BuildSolution" <== ["Clean"; "RestorePackages"] 24 | 25 | RunTargetOrDefault "BuildSolution" 26 | --------------------------------------------------------------------------------