Bot releases are hidden (Show)
Published by louthy about 9 years ago
Removed dependency on System.Collections.Immutable
. All immutable types are implemented in-project:
Lst<T>
Map<K,V>
Set<T>
Que<T>
Stck<T>
Either
and EitherUnsafe
API rebalancing (between Left and Right behaviours). Also Either
and EitherUnsafe
are now bifunctors, bifoldable and bitraversible.
Compose
and BackCompose
extension methods for Func<A,B>
. Also, new compose
function in the Prelude
NuGet:
Published by louthy about 9 years ago
This is a major new release of Language-Ext with myriad new features and improvements. Much of this release is about refining and standardising the API. This is the first stable release of the LanguageExt.Process
system (Actor system), LanguageExt.Process.FSharp
(F# API for LanguageExt.Process
), LanguageExt.ProcessJS
(Javascript Actor system that allows seamless actor messaging from server to client), and LanguageExt.Process.Redis
(for intra-system messaging and message/state persistence).
Standardisation comes in the form:
So:
tuple
becomes Tuple
list
becomes List
map
becomes Map
cons
becomes Cons
This makes the constructor functions consistent with Some
, None
, Left
, Right
, ... The only exception to this is the unit
constructor, which stays as-is.
We also bring in a concept of a type of a 'higher kinded type' for all of the monadic types. It's not quite as effective or refined as a Haskell HKT, but it does create a standard interface (through extension methods) for all of the monadic types. The standard interface includes the following functions:
Sum
Count
Bind
Exists
Filter
Fold
ForAll
Iter
Map
Lift
/ LiftUnsafe
SelectMany
Select
Where
Because of this standardised interface, it's also possible to use monad transformer functions (for up to a two-level deep generic monad-type):
SumT
BindT
CountT
ExistsT
FilterT
FoldT
ForAllT
IterT
MapT
i.e.
var list = List(Some(1), None, Some(2), None, Some(3)); // Lst<Option<int>>
var presum = list.SumT(); // 6
list = list.MapT( x => x * 2 );
var postsum = list.SumT(); // 12
Map<K,V>
- Replacement for ImmutableDictionary<K,V>
that uses an AVL tree implementationLst<T>
- Wrapper for ImmutableList<T>
Set<T>
- Wrapper for ImmutableSet<T>
Try<T>
- Like TryOption<T>
but without the optional return valueRWS<E,W,S>
- Reader/Writer/State monadExceptionMatch
- Used for new Exception
extension method Match
for pattern matching on exception types.ActionObservable<T>
- Used by IObservable<T>
extension method PostSubscribe
. Allows an action to be executed post-subscription.LanguageExt.Process
par
- Partial applicationcurry
- Curryingrandom
- Thread safe random number generatorifSome
added for TryOption
- dispatches an action if the TryOption
is in a Some
stateUnit
type - Implemented IEquatable<Unit>
and equality operator overloadsIComparable
and IEquatable
support for Option
and Either
typesfold
and scan
delegates to Func<S,T,S>
tuple
- becomes Tuple
query
- becomes Query
map
- becomes Map
list
- becomes List
array
- becomes Array
stack
- becomes Stack
failure
- becomes ifNone
/ ifLeft
Prelude.empty
- becomes List.empty
/ Set.empty
/ Map.empty
cons
- becomes Cons
range
- becomes Range
with
- becomes map
Nuget:
Published by louthy over 9 years ago
Now that System.Collections.Immutable
has been fully released (as version 1.1.36) we can now do a full release of Language-Ext.
As usual you can find the package on NuGet
Use and abuse the features of C#, which, if you squint, can look like extensions to the language itself. This package is a functional 'toolkit' and also solves some of the annoyances with C#, namely:
Option
, Either
, Unit
, ...)The library very heavily focusses on correctness, to give you the tools needed to write safe declarative code.
Features:
Powerful 'prelude' which you include by using static LanguageExt.Prelude
(in C# 6) that covers many of the basic functional language core library functions and types (from using LanguageExt
):
var fn = fun( (int x, int y) => x + y );
Option<T>
, OptionUnsafe<T>
, Either<L,R>
, EitherUnsafe<L,R>
and TryOption<T>
monads (probably the most complete implementations you'll find in the .NET world)tuple(a,b,...)
- Tuple
construction without typing Tuple.Create(a,b,...)
as well as map
to project the Item1..ItemN
properties onto named values.List
- immutable listMap
- immutable mapSet
- immutable setmemo
- Memoization with auto-cache purging using weak-referencesWriter
monadReader
monadState
monadout
(Int32.TryParse
, IDictionary.TryGetValue
, etc.)This only skims the surface of the library
Additions:
Reader<E,T>
monad
Prelude.Reader
constructor functionPrelude.ask
functionPrelude.local
functionWriter<W,T>
monad
Prelude.Writer
constructor functionPrelude.tell
functionState<S,T>
monad
Prelude.State
constructor functionPrelude.get
functionPrelude.put
functionOption<T>
IfSome
method for dispatching actions and ignoring None
Prelude.ifSome
as aboveIfNone
method (replaces Failure
)Prelude.ifNone
function (replaces Prelude.failure
)ToEither
converts an Option<T>
to an Either<L,R>
(you must provide a default(L) value or func incase the Option
is in a None
state)ToEitherUnsafe
converts an Option<T>
to an EitherUnsafe<L,R>
(you must provide a default(L) value or func incase the Option is in a None state)Some
fluent method now also supports Action
OptionUnsafe<T>
IfSomeUnsafe
method for dispatching actions and ignoring None
Prelude.ifSomeUnsafe
as aboveIfNoneUnsafe
method (replaces FailureUnsafe
)Prelude.ifNoneUnsafe
function (replaces Prelude.failureUnsafe
)ToEitherUnsafe
converts an OptionUnsafe<T>
to an EitherUnsafe<L,R>
(you must provide a default(L) value or func incase the OptionUnsafe is in a None state)Some
fluent method now also supports Action
TryOption<T>
IfSome
method for dispatching actions and ignoring None
or Fail
Prelude.ifSome
as aboveIfNone
method (replaces Failure
)Prelude.ifNone
function (replaces Prelude.failure
)IfNoneOrFail
method for handling both failure states separately (Some state uses identity function)Prelude.ifNoneOrFail
as aboveTryOptionConfig.ErrorLogger
static variable which can be used to attach error logging behaviour to the Fail
state of TryOption
Prelude.tryfun
function wraps a TryOption
in a Func
ToOption
converts a TryOption<T>
to a Option<T>
(Fail becomes None)Some
fluent method now also supports Action
Either<L,R>
IfRight
method for dispatching actions and ignoring Left
Prelude.ifRight
as aboveIfLeft
method (replaces Failure
)Prelude.ifLeft
method (replaces Prelude.failure
)Right
fluent method now also supports Action
ToOption
converts an Either<L,R>
to an Option<R>
(L
becomes None
)ToTryOption
converts an Either<L,R>
to a TryOption<R>
ToEitherUnsafe
converts an Either<L,R>
to an EitherUnsafe<L,R>
(L
becomes None
)EitherUnsafe<L,R>
IfRightUnsafe
method for dispatching actions and ignoring Left
Prelude.ifRightUnsafe
as aboveIfLeftUnsafe
method (replaces FailureUnsafe
)Prelude.ifLeftUnsafe
method (replaces Prelude.failureUnsafe
)Right
fluent method now also supports Action
Updates:
Prelude.convert<T>
now returns None
if input is null
(it previously threw an exception)Fixes:
Deprecated:
ConcurrentHashTable
failure
and Failure
(for ifNone
, IfNone
, ifLeft
, etc.)Iter
extension method in Query
, it was causing resolution problems for the compiler.RightUnsafe
and LeftUnsafe
from Either
, these were a hangover from when EitherUnsafe
didn't exist and Either
had a dual role. This isn't needed any more.Published by louthy over 9 years ago
Deprecated headSafe
Added headOrNone
for safely finding the optional head item in a collection
Added Query
namespace (static class) for working with IQueryable
. Has functions:
headOrNone
tail
map
filter
choose
collect
sum
rev
append
fold
foldBack
reduce
reduceBack
find
freeze
zip
length
iter
forall
distinct
take
takeWhile
exists
Option
and Some
TypeConverter supportPublished by louthy over 9 years ago
Either<R,L>
becomes:
Either<L,R>
Warning: if you're currently using Either
then getting the latest will break your compilation. You will need to update all usages of Either<R,L>
to Either<L,R>
, which is potentially tedious for large projects. Please be warned.
Normally I wouldn't do such a big breaking change. But I have finally been convinced that this is the correct way and I think it's best to just bite the bullet and get it done. Apologies if this causes headaches, I promise it won't happen again!
Latest on nuget: https://www.nuget.org/packages/LanguageExt/
Published by louthy over 9 years ago
None
and Left
coalescing using the logical-or operator.
This means chaining of optional values with defaults:
Option<int> optional1 = None;
Option<int> optional2 = None;
var res = optional1 || optional2 || "Default";
// Some("Default")
This also means you can use them in LINQ expressions where from
is logical-AND and ||
is logical-OR:
Option<int> optional1 = None;
Option<int> optional2 = Some(10);
Option<int> optional3 = Some(20);
var res = from x in optional1 || optional2
from y in optional3
select x + y;
// Some(30)
true
and false
operators implemented for option and either types.
var optional = Some(123);
if( optional )
{
// true
}
==
and !=
operators implemented for option and either types:
var optional = Some(123);
if( optional == 123 )
{
// true
}
Option<int> optional = None;
if( optional == None )
{
// true
}
with(Tuple,..)
and With(Tuple,..)
are now map(Tuple,..)
and Map(Tuple,..)
. They were poorly named, these are more consistent with their action. The with
functions that take up to 5 parameters are also renamed map
.
The old with
functions have been marked [Obsolete]
Thanks to @tomaszpolanski for the feedback
https://github.com/louthy/language-ext/issues/15
Added Optional
, it will take T
or null
and return a Some(T)
or None
respectively. This is for where you want to be explicit about the conversion from T
to Some(T)|None
, and for when the type system complains at you (in the branches of a ternary operator for example):
string x = GetValueFromNonTrustedAPI();
return Optional(x);
Thanks to @tejacques for the feedback:
https://github.com/louthy/language-ext/issues/12
... and Various bug fixes
Published by louthy almost 10 years ago
Improved list matching. There are many more overrides for deconstructing the head items from a list (up to six elements). e.g.
// The fewest number of elements deconstructed
int Product(IEnumerable<int> list) =>
match(list,
() => 1,
(x, xs) => x * Product(xs));
// The most
int GetLength(IEnumerable<int> list) =>
match(
lst,
() => 0,
a => 1,
(a, b) => 2,
(a, b, c) => 3,
(a, b, c, d) => 4,
(a, b, c, d, e) => 5,
(a, b, c, d, e, f) => 6,
(x, xs) => xs.Count() + 1
);
Also, a null
list is considered empty.
Additional range()
variants:
range(0,100,10)
range( range(0,100), range(200,100) )
range('a','z')
Additional functions:
repeat
init
- generate a sequence where each step calls a generator function with the indexinitInfinite
choose
collect
scan
scanBack
find
distinct
take
takeWhile
unfold
exists
Breaking changes
foldr
renamed foldBack
map
and iter
(mapi
and iteri
) and just used overloading insteadAdditional function:
exists
Breaking changes
contains
renamed containsKey
Additional functions:
add
compare
length
difference
exists
filter
intersect
map
contains
remove
isSubset
isProperSubset
Breaking change
this
from with
, they shouldn't be extension methods because With
is already performing that duty.convert
returns Option<T>
TryGetValue
for ImmutableDictionary
and ImmutableSet
AsEnumerable()
extension to Nullable<T>
toList
, toArray
, toSet
, toQueue
, toStack
On NuGet now: https://www.nuget.org/packages/LanguageExt/
Published by louthy almost 10 years ago
List pattern matching:
public int Sum(IEnumerable<int> list) =>
match( list,
() => 0,
x => x,
(x, xs) => x + Sum(xs) );
Extension methods for lifting Option
, OptionUnsafe
, Either
, EitherUnsafe
when wrapped by an IEnumerable
.
TryOption<T>.AsEnumerable()
now returns an IEnumerable<Either<T,Exception>>
instead of burying the Exception
as an empty list. The extension methods above can be used to easily extract the value from the IEnumerable<Either<T,Exception>>
. This puts control back in the programmer's hands about what to do with the possible failed state of the TryOption
.
e.g.
// Ignore all errors, and return an empty list
var res = (from v in GetTryOptionError().AsEnumerable().FailWithEmpty()
from r in range(1, 10)
select v * r);
// Ignore the errors and provide a sensible default
var res = (from v in GetTryOptionValue(false).AsEnumerable().Failure( list(1) )
from r in range(1, 10)
select v * r);
// Recognise the error, and throw
var res = (from v in match(
GetTryOptionValue(true).AsEnumerable(),
Right: r => list(r),
Left: ex => failwith<int>("broken: " + ex.Message)
)
from r in range(1, 10)
select v * r);
Check LinqTests.cs and ListMatchingTests.cs for examples.
Published by louthy almost 10 years ago
New functions for Option, OptionUnsafe, TryOption:
New functions in List and Map:
Improved memoization:
Func<T,R>
. In a unit-test memoizing 0 -> Int32.MaxValue strings, the NUnit runner never jumped above 45mb.Breaking changes:
Published by louthy almost 10 years ago
New TryOption<T>
type for catching all three possible outputs of a function: value
, null
, Exception
. With three branches in Match
: Some
|None
|Fail
.
Option<T>
and Either<R,L>
have been split in to Option<T>
, OptionUnsafe<T>
, Either<R,L>
and EitherUnsafe<R,L>
. The 'unsafe' variants are for the cases where null
is actually a valid Some
value. They are only 'unsafe' because the of this reason.
Construction of OptionUnsafe<T>
and EitherUnsafe<R,L>
is done using SomeUnsafe(value)
, RightUnsafe(value)
, LeftUnsafe(value)
. Matching is done using matchUnsafe(...)
and failureUnsafe
.
This is much more declarative, and will clearly bias the programmer toward the safe types, only opting out when they absolutely need null
as a valid value.
Breaking change: set
becomes setItem
.
New prelude functions | Description |
---|---|
stack<T>() |
Create an IImmutableStack |
set<T>() |
Create an IImmutableHashSet |
array<T>() |
Create an ImmutableArray |
queue<T>() |
Create an IImmutableQueue |
New List functions | Description |
---|---|
freeze | Takes an IEnumerable and turns it into an IImmutableList |
zip | Wrapper for Enumerable.Zip |
length | Wrapper for IImmutableList.Count() |
New Map functions | Description |
---|---|
length | Wrapper for IImmutableDictionary.Count() |
Published by louthy almost 10 years ago
Option and Either updates
Some(null)
now doesn't coerce to a None
, a ValueIsNullException
will be thrownSome(Nullable<T>)
supported, will coerce the Value
to Some
if HasValue
is true
, otherwise a ValueIsNullException
will be thrownRight(Nullable<T>)
/Left(Nullable<T>)
supported, will coerce the Value
to Right
/Left
if HasValue
is true, otherwise a ValueIsNullException
will be thrownSomeUnsafe()
added : Allows Some(null)
and allows the Some
and None
branches of match
to return null
.RightUnsafe()
/LeftUnsafe()
added : Allows Right(null)
and Left(null)
and allows the Right
and Left
branches of match to return null
.IsUnsafe
to Option<T>
and Either<R,L>
I'm considering whether the 'unsafe' variants should return a OptionUnsafe<T>
and EitherUnsafe<R,L>
to make it explicit that the Some
,Right
and Left
branches could have null
and that's a valid result. I'm inviting feedback...