Skip to content

Instantly share code, notes, and snippets.

@jeremyrsellars
Last active January 24, 2019 12:51
Show Gist options
  • Save jeremyrsellars/3c89569147980f7849290f6f6f58d5af to your computer and use it in GitHub Desktop.
Save jeremyrsellars/3c89569147980f7849290f6f6f58d5af to your computer and use it in GitHub Desktop.
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