Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

C# pure functional programming framework - come and get declarative!

License

NotificationsYou must be signed in to change notification settings

louthy/language-ext

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

lang-ext

C# Functional Programming Language Extensions

This library uses and abuses the features of C# to provide a pure functional-programming framework that, if you squint, can look likeextensions to the language itself. The desire here is to make programming in C# much more robust by helping the engineer's inertia flowin the direction of declarative and pure functional code rather than imperative. Using these techniques for large code-bases can bringtangible benefits to long-term maintenance by removing hidden complexity and by easing the engineer's and team's cognitive load.

GitHub Discussions

Author on...

Contents

Reference

Nu-get

Nu-get packageDescription
LanguageExt.ParsecPort of theHaskell parsec library
LanguageExt.StreamingA set of compositional streaming types
LanguageExt.FSharpF# to C# interop package. Provides interop between the LanguageExt.Core types (likeOption,List andMap) to the F# equivalents, as well as interop between core BCL types and F#
LanguageExt.ParsecPort of theHaskell parsec library
LanguageExt.RxReactive Extensions support for various types within the Core
LanguageExt.SysProvides an effects wrapper around the .NET System namespace making common IO operations pure and unit-testable

lang-ext

Getting started

To use this library, simply includeLanguageExt.Core.dll in your project or grab it from NuGet. It is also worth setting up someglobal using for your project. This is the full list that will cover all functionality and bring it into scope:

globalusingLanguageExt;globalusingLanguageExt.Common;globalusingLanguageExt.Traits;globalusingLanguageExt.Effects;globalusingLanguageExt.Streaming;globalusingLanguageExt.Pretty;globalusingLanguageExt.Traits.Domain;globalusingstaticLanguageExt.Prelude;

A minimum, might be:

globalusingLanguageExt;globalusingstaticLanguageExt.Prelude;

The namespaceLanguageExt contains most of the core types;LanguageExt.Prelude contains the functions that bring into scope the prelude functions that behave like standalone functions in ML style functional programming languages;LanguageExt.Traits brings in the higher-kinded trait-types and many extensions;LanguageExt.Common brings in theError type and predefinedErrors.

Prologue

From C# 6 onwards we got the ability to treat static classes like namespaces. This means that we can use staticmethods without qualifying them first. That instantly gives us access to single term method names that look exactly like functionsin ML-style functional languages. i.e.

usingstaticSystem.Console;WriteLine("Hello, World");

This library tries to bring some of the functional world into C#. It won't always sit well with the seasoned C# OO programmer,especially the choice ofcamelCase names for a lot of functions and the seeming 'globalness' of a lot of the library.

I can understand that much of this library is non-idiomatic, but when you think of the journey C# has been on, is "idiomatic"necessarily right? A lot of C#'s idioms are inherited from Java and C# 1.0. Since then we've had generics, closures, Func, LINQ,async... C# as a language is becoming more and more like a functional language on every release. In fact, the bulk of the newfeatures are either inspired by or directly taken from features in functional languages. So perhaps it's time to move the C#idioms closer to the functional world's idioms?

My goal with this library is very much to create a whole new community within the larger C# community. This community is notconstrained by the dogma of the past or by the norms of C#. It understands that the OOP approach to programming has some problemsand tries to address them head-on.

And for those that say "just use F#" or "just use Haskell", sure, go do that. But it's important to remember that C# has a lotgoing for it:

  • Incredible investment into a state-of-the art compiler
  • Incredible tooling (Visual Studio and Rider)
  • A large ecosystem of open-source libraries
  • A large community of developers already using it
    • This is also very important for companies that hire engineers
  • Itis a functional programming language! It has first-class functions, lambdas, etc.
    • And with this library it has a functional-firstBase Class Library

A note about naming

One of the areas that's likely to get seasoned C# heads worked up is my choice of naming style. The intent is to try and makesomething thatfeels like a functional language rather than following rules of naming conventions (mostly set out bythe BCL).

There is, however, a naming guide that will keep you in good stead while reading through this documentation:

  • Type names arePascalCase in the normal way
  • The types all have constructor functions rather than public constructors that you instantiate withnew. They will alwaysbePascalCase:
Option<int>x=Some(123);Option<int>y=None;Seq<int>items=Seq(1,2,3,4,5);List<int>items=List(1,2,3,4,5);HashMap<int,string>dict=HashMap((1,"Hello"),(2,"World"));Map<int,string>dict=Map((1,"Hello"),(2,"World"));
  • Any (non-type constructor) static function that can be used on its own byusing static LanguageExt.Prelude arecamelCase.
varx=map(opt, v=>v*2);
  • Any extension methods, or anything "fluent" arePascalCase in the normal way
varx=opt.Map(v=>v*2);

Even if you disagree with this non-idiomatic approach, all of thecamelCase static functions have fluent variants, so you never actually have to see the non-standard stuff.

Features

LocationFeatureDescription
CoreIO<A>A synchronous and asynchronous side-effect: an IO monad
CoreEff<A>A synchronous and asynchronous side-effect with error handling
CoreEff<RT, A>Same asEff<A> but with an injectable runtime for dependency-injection: a unit testable IO monad
LocationFeatureDescription
CoreAtom<A>A lock-free atomically mutable reference for working with shared state
CoreRef<A>An atomic reference to be used in the transactional memory system
CoreAtomHashMap<K, V>An immutableHashMap with a lock-free atomically mutable reference
CoreAtomSeq<A>An immutableSeq with a lock-free atomically mutable reference
CoreVectorClock<A>Understand distributed causality
CoreVersionVector<A>A vector clock with some versioned data
CoreVersionHashMap <ConflictV, K, V>Distrubuted atomic versioning of keys in a hash-map
LocationFeatureDescription
CoreArr<A>Immutable array
CoreSeq<A>Lazy immutable list, evaluate at-most-once - very, very fast!
CoreIterable<A>Wrapper aroundIEnumerable with support for traits - enables the higher-kinded traits to work with enumerables.
CoreLst<A>Immutable list - useSeq overLst unless you needInsertAt
CoreMap<K, V>Immutable map
CoreMap<OrdK, K, V>Immutable map with Ord constraint onK
CoreHashMap<K, V>Immutable hash-map
CoreHashMap<EqK, K, V>Immutable hash-map with Eq constraint onK
CoreSet<A>Immutable set
CoreSet<OrdA, A>Immutable set with Ord constraint onA
CoreHashSet<A>Immutable hash-set
CoreHashSet<EqA, A>Immutable hash-set with Eq constraint onA
CoreQue<A>Immutable queue
CoreStck<A>Immutable stack
LocationFeatureDescription
StreamingPipesConnect reusable streaming components into a closed effect
StreamingSinkEntry point to a channel. Sinks receive values and propagate them through a channel
StreamingSinkTAs above but with effects
StreamingSourceStream of synchronous or asynchronous values depending on the construction. Values flow downstream and are aggregated with a reducer.
StreamingSourceTAs above but with effects
StreamingConduitRepresents a channel with an internal queue. The conduit has aSink and aSource allowing items to be posted into the conduit, co-mapped, mapped, and consumed.
StreamingConduitTAs above but with effects: the conduit has aSinkT and aSourceT allowing items to be posted into the conduit, co-mapped, mapped, and consumed.
LocationFeatureDescription
CoreOption<A>Option monad
CoreOptionT<M, A>Option monad-transformer
CoreEither<L,R>Right/Left choice monad
CoreEitherT<L, M, R>Right/Left choice monad-transformer
CoreFin<A>Error handling monad, likeEither<Error, A>
CoreFinT<M, A>Error handling monad-transformer
CoreTry<A>Exception handling monad
CoreTryT<M, A>Exception handling monad-transformer
CoreValidation<FAIL ,SUCCESS>Validation applicative and monad for collecting multiple errors before aborting an operation
CoreValidationT<FAIL, M, SUCCESS>Validation applicative and monad-transformer
LocationFeatureDescription
CoreReader<E, A>Reader monad
CoreReaderT<E, M, A>Reader monad-transformer
CoreWriter<W, A>Writer monad that logs to aW constrained to be a Monoid
CoreWriterT<W, M, A>Writer monad-transformer
CoreState<S, A>State monad
CoreStateT<S, M, A>State monad-transformer
LocationFeatureDescription
ParsecParser<A>String parser monad and full parser combinators library
ParsecParser<I, O>Parser monad that can work with any input stream type
LocationFeatureDescription
CoreDoc<A>Produce nicely formatted text with smart layouts
LocationFeatureDescription
CorePatch<EqA, A>Uses patch-theory to efficiently calculate the difference (Patch.diff(list1, list2)) between two collections ofA and build a patch which can be applied (Patch.apply(patch, list)) to one to make the other (think git diff).

The traits are major feature ofv5+ language-ext that makes generic programming with higher-kinds a reality. Check out Paul'sseries on Higher Kinds to get a deeper insight.

LocationFeatureDescription
CoreApplicative<F>Applicative functor
CoreEq<A>Ad-hoc equality trait
CoreFallible<F>Trait that describes types that can fail
CoreFoldable<T>Aggregation over a structure
CoreFunctor<F>FunctorMap
CoreHas<M, TRAIT>Used in runtimes to enable DI-like capabilities
CoreHashable<A>Ad-hoc has-a-hash-code trait
CoreLocal<M, E>Creates a local environment to run a computation
CoreMonad<M>Monad trait
CoreMonadT<M, N>Monad transformer trait
CoreMonoid<A>A monoid is a type with an identityEmpty and an associative binary operation+
CoreMonoidK<M>Equivalent of monoids for working on higher-kinded types
CoreMutates<M, OUTER_STATE, INNER_STATE>Used in runtimes to enable stateful operations
CoreOrd<A>Ad-hoc ordering / comparisons
CoreRange<SELF, NumOrdA, A>Abstraction of a range of values
CoreReadable<M, Env>Generalised Reader monad abstraction
CoreSemigroup<A>Provides an associative binary operation+
CoreSemigroupK<M>Equivalent of semigroups for working with higher-kinded types
CoreStateful<M, S>Generalised State monad abstraction
CoreTraversable<T>Traversable structures support element-wise sequencing of Applicative effects
CoreWritable<M, W>Generalised Writer monad abstraction

These work a little like type-aliasing but they impart semantic meaning and some common operators for the underlying value.

LocationFeatureDescription
CoreDomainType<SELF, REPR>Provides a mapping fromSELF to an underlying representation:REPR
CoreIdentifier <SELF>Identifiers (like IDs in databases:PersonId for example), they are equivalent toDomaintType with equality.
CoreVectorSpace<SELF, SCALAR>Scalable values; can add and subtract self, but can only multiply and divide by a scalar. Can also negate.
CoreAmount <SELF, SCALAR>Quantities, such as the amount of money in USD on a bank account or a file size in bytes. DerivesVectorSpace,IdentifierLike,DomainType, and is orderable (comparable).
CoreLocus <SELF, DISTANCE, SCALAR>Works with space-like structures. Spaces have absolute and relative distances. Has an origin/zero point and derivesDomainType,IdentifierLike,AmountLike andVectorSpace.DISTANCE must also be anAmountLike<SELF, REPR, SCALAR>.

These features are still a little in-flux as of 17th Oct 2024 - they may evolve, be renamed, or removed - but I like the idea!

Further

For some non-reference like documentation:

  • Paul's blog:Notes from a Small Functional Island does deep dives into the philosophy of FP and the inner-workings of language-ext.
  • The wiki has some additional documentation, some might be a little out of date since the bigv5 refactor, but should give some good insights.

Contributing & Code of Conduct

If you would like to get involved with this project, please first read theContribution Guidelines and theCode of Conduct.

Sponsor this project

  •  

Packages

No packages published

Languages


[8]ページ先頭

©2009-2025 Movatter.jp