LanguageExt Documentation

repository·main·Indexed 27 days ago

https://github.com/louthy/language-ext

A pure functional-programming framework for C# providing extensions for declarative and robust programming. It includes functional effects (IO, Eff), immutable collections (Seq, Iterator, IteratorAsync), concurrency primitives (Atoms, STM), and a functional error handling system using the Error type. The library implements Haskell-style typeclass instances via 'Class Instances' to enable ad-hoc polymorphism without boxing.

Tokens
23.9K
Snippets
38
Records
143
Agent score
92%

What's inside LanguageExt

  1. Understand the Alternative<F> trait

    main

    The Alternative<F> trait is used for types that support the propagation of 'failure' and 'choice', as well as the provision of a unit/identity value called Empty.

    An Alternative type is both a Choice and a MonoidK. It provides three primary methods:

    • Choose: The failure/choice propagation operator, semantically represented by the | operator.
    • Combine: The concatenation/combination/addition operator, semantically represented by the + operator. By default, Combine calls Choose.
    • Empty: Returns the identity/unit value for the type.
  2. Functional effects and IO

    main

    Language-ext provides monads for managing side-effects and IO operations in a functional way.

    • IO<A>: A monad representing both synchronous and asynchronous side-effects.
    • Eff<A>: A monad for synchronous and asynchronous side-effects that includes built-in error handling.
    • Eff<RT, A>: An effect monad with an injectable runtime (RT) for dependency injection, making it unit-testable.
  3. New Features in Language-Ext v2.0

    main

    Language-Ext v2.0 introduces advanced functional programming capabilities to C#:

    • Ad-hoc Polymorphism: Uses a technique to allow writing methods for all numeric types or structural equality testing once, similar to Haskell typeclasses.
    • Higher-Order Polymorphic Types: Provides type-safe support for working with higher-order types like Monad<MA, A>. You can now write functions that accept monads, functors, or applicatives and return specialized values rather than abstract or dynamic ones.
    • Enhanced Transformer Extensions: The Writer monad can now work with any output type that has a Monoid instance (e.g., Lst, string, int), rather than being limited to IEnumerable.
  4. Understand Closed Streams with Pipes

    main

    Closed streams are implemented via the Pipes system. These are compositional monad-transformers that 'fuse' together using the | operator to produce an EffectT<M, A> (or Effect<RT, A> for specialized versions). Once fused, the system is 'closed,' meaning you cannot interact with the effect directly from the outside; you can only execute it to receive a result upon termination.

    Pipeline Components:

    • ProducerT<OUT, M, A>: Produces values.
    • PipeT<IN, OUT, M, A>: Transforms values.
    • ConsumerT<IN, M, A>: Consumes values.

    Specialized Versions (for Eff<RT, A>):

    • Producer<RT, OUT, A>
    • Pipe<RT, IN, OUT, A>
    • Consumer<RT, IN, A>
  5. Understand the MonoidK<F> trait

    main

    The MonoidK<F> trait is a monoid for higher-kinds (types of the form K<F, A>). It inherits from SemigroupK<F> and provides an Empty() value (the identity/zero element) and the ability to Combine two K<F, A> structures.

    In many implementations, Combine behaves similarly to the C# ?? operator: if the first argument fails, it returns the second; if the first succeeds, it returns the result of the first. This allows for error propagation and alternative structure coalescing.

  6. Understand the Pipes abstraction

    main

    The Pipes module provides a framework for effectful, streaming, and composable programming in constant memory. It decouples stream processing stages, allowing you to mix and match components to build efficient pipelines.

    Key features include:

    • Effectful: Supports interleaving side-effects within the stream.
    • Streaming: Processes data in constant space.
    • Composable: Components are modular and can be connected using the | operator.

    Components communicate via two primary commands:

    • yield: Send output data downstream.
    • awaiting: Receive input data from upstream.
  7. Understand Lenses for immutable data access and updates

    main
    Lenses provide a functional way to look inside a data structure to access a specific value and subsequently update that value. Because language-ext promotes immutability, Lenses do not mutate the original structure; instead, the updater functions return a new version of the underlying structure with the value modified.
  8. Use Open Streams (Source, Sink, Conduit)

    main

    Open streams are designed for public manipulation, similar to IObservable or events. They allow you to Post values to a Sink or Reduce values yielded by a Source.

    Core Types:

    • Source<A> / SourceT<M, A>: Yields values (synchronously or asynchronously). SourceT is a monad-transformer that allows embedding side effects using a MonadIO-enabled monad M (e.g., SourceT<IO, A>).
    • Sink<A> / SinkT<M, A>: Receives and buffers values. They act like a System.Threading.Channels.Channel that can manipulate values via Comap (as CoFunctors) before they are stored.
    • Conduit<A, B> / ConduitT<M, A, B>: An input transducer (acts like a Sink), an internal buffer, and an output transducer (acts like a Source).
  9. Understand the Choice<F> trait for failure and choice propagation

    main

    The Choice<F> trait is used to propagate 'failure' and 'choice' within a type. It provides two primary semantic operations for combining values:

    1. Choice Propagation (|): Handled by the Choose method. This operator is used for failure/choice propagation. If one side is a failure, the other side is typically preferred (unless both are failures).
    2. Combination/Concatenation (+): Handled by the Combine method (inherited from SemigroupK). This operator is used for concatenation, combination, or addition of values.

    When implementing or using a type with the Choice trait, you can use the | operator for choice propagation and the + operator for combination.

  10. Atomic concurrency and collections

    main

    Manage shared state and distributed causality using lock-free and transactional primitives.

    Concurrency Primitives:

    • Atom<A>: A lock-free atomically mutable reference for shared state.
    • Ref<A>: An atomic reference designed for use within the Software Transactional Memory (STM) system.
    • VectorClock<A>: Tools to understand distributed causality.
    • VersionVector<A>: A vector clock that carries versioned data.
    • VersionHashMap<ConflictV, K, V>: Provides distributed atomic versioning for keys in a hash map.

    Atomic Collections:

    • AtomHashMap<K, V>: An immutable HashMap wrapped in a lock-free atomically mutable reference.
    • AtomSeq<A>: An immutable Seq wrapped in a lock-free atomically mutable reference.
  11. Understand Alternative Monads in LanguageExt

    main

    In LanguageExt, an Alternative Monad is a monadic type that represents a choice between two types: a Bound Value (the primary value being processed) and an Alternative Value (typically used to carry error information or a fallback state).

    Conceptually, while a tuple (int, string) represents an int AND a string, an alternative monad like Either<int, string> represents an int OR a string. The Right value in Either is the bound value, and the Left value is the alternative value.

  12. Explore monadic types in LanguageExt

    main

    The LanguageExt.Core library provides a wide range of monadic types. While this specific section contains many of them, other specialized monadic types are organized into different modules: