Last active
January 24, 2019 12:51
-
-
Save jeremyrsellars/3c89569147980f7849290f6f6f58d5af to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
using System; | |
using System.Threading; | |
namespace Sellars.Functional.Fluent | |
{ | |
static class FunctionalExtensions | |
{ | |
/// <summary> | |
/// Creates a <see cref="Lazy{T}"/> from <see cref="valueFactory"/>. | |
/// </summary> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="valueFactory"></param> | |
/// <param name="mode"></param> | |
/// <returns></returns> | |
public static Lazy<T> ToLazy<T>(this Func<T> valueFactory, LazyThreadSafetyMode mode) => | |
new Lazy<T>(valueFactory, mode); | |
/// <summary> | |
/// Returns a <see cref="Func{T1}"/> that calls <see cref="Func{T}"/> with <paramref name="func"/> with <paramref name="arg1"/>. | |
/// </summary> | |
/// <typeparam name="T1"></typeparam> | |
/// <typeparam name="T"></typeparam> | |
/// <param name="func"></param> | |
/// <param name="arg1"></param> | |
/// <returns></returns> | |
public static Func<T> Partial<T1,T>(this Func<T1,T> func, T1 arg1) => () => func(arg1); | |
/// <summary> | |
/// Transforms the output of <paramref name="func"/> with <paramref name="transform"/>, | |
/// effectively yielding <c>x => transform(func(x))</c>. | |
/// </summary> | |
/// <typeparam name="TIn"></typeparam> | |
/// <typeparam name="TOut"></typeparam> | |
/// <param name="func"></param> | |
/// <param name="transform"></param> | |
/// <returns></returns> | |
public static Func<TOut> Transform<TIn, TOut>(this Func<TIn> func, Func<TIn, TOut> transform) => | |
() => transform(func()); | |
/// <summary> | |
/// Returns a memoized version of <paramref name="valueFactory"/>, which caches result of calling <see cref="valueFactory"/> | |
/// by its input argument, so the value need only be created once. | |
/// This potentially improves performance by trading memory usage for one-time creation semantics. | |
/// </summary> | |
/// <typeparam name="TIn"></typeparam> | |
/// <typeparam name="TOut"></typeparam> | |
/// <param name="valueFactory"> | |
/// A <see cref="Func{T}"/> that is free of side-effects, or whose effects may be safely run multiple times if accessed from multiple threads concurretly. | |
/// </param> | |
/// <returns>A <see cref="Func{T}"/> that is logically equivalent to <paramref name="valueFactory"/>.</returns> | |
public static Func<TIn,TOut> Memoize<TIn,TOut>(this Func<TIn,TOut> valueFactory) | |
{ | |
if (valueFactory == null) | |
throw new ArgumentNullException(nameof(valueFactory)); | |
var memoizationCache = Atom.Create(ImmutableDictionary<TIn, TOut>.Empty); | |
TOut GetOrAdd(TIn key) | |
{ | |
ImmutableDictionary<TIn, TOut> Transition(ImmutableDictionary<TIn, TOut> cache) => | |
cache.ContainsKey(key) ? cache : cache.Add(key, valueFactory(key)); | |
return memoizationCache.Value.TryGetValue(key, out var value) | |
? value | |
: memoizationCache.SwapAndDeref(Transition)[key]; | |
} | |
return GetOrAdd; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment