Skip to content

Instantly share code, notes, and snippets.

@EliahKagan
Last active April 1, 2020 00:05
Show Gist options
  • Save EliahKagan/a1405b72245ae1decfaa027035c74805 to your computer and use it in GitHub Desktop.
Save EliahKagan/a1405b72245ae1decfaa027035c74805 to your computer and use it in GitHub Desktop.

Fibonacci memoized - recursive anonymous functions

This gist contains examples of recursive anonymous functions, implemented with various techniques, in C++, Java, and C#.

Files named like *.linq.cs are really .linq files. The extra .cs suffix is to get C# syntax highlighting.

import java.math.BigInteger;
import java.util.HashMap;
import java.util.function.IntFunction;
final class AnonymousClassFibonacci {
public static void main(String[] args) {
var memo = new HashMap<Integer, BigInteger>();
memo.put(0, BigInteger.ZERO);
memo.put(1, BigInteger.ONE);
var fib = new IntFunction<BigInteger>() {
@Override
public BigInteger apply(int n) {
if (n < 0)
throw new IllegalArgumentException("n must be nonnegative");
var result = memo.getOrDefault(n, null);
if (result != null) return result;
result = apply(n - 2).add(apply(n - 1));
memo.put(n, result);
return result;
}
};
System.out.println(fib.apply(10));
System.out.println(fib.apply(1000));
}
}
cmake_minimum_required(VERSION 3.0.0)
project(fibonacci-memoized VERSION 0.1.0)
include(CTest)
enable_testing()
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
if(MSVC)
# cl and clang-cl accept /W4 (but -Weverything will override in clang-cl).
string(REGEX REPLACE /W[123] /W4 CMAKE_CXX_FLAGS ${CMAKE_CXX_FLAGS})
# cl and clang-cl accept /permissive- for stricter conformance.
add_compile_options(/permissive-)
else()
# gcc/g++ and clang/clang++ require comparably strict conformance to
# /permissive- unless -fpermissive is passed. But they accept -pedantic
# for even more conformance warnings, and -pedantic-errors for errors.
add_compile_options(-pedantic-errors)
endif()
if(${CMAKE_CXX_COMPILER_ID} STREQUAL "Clang")
# Clang accepts -Weverything with both clang/clang++ and clang-cl.
# We will keep all but a few of the warnings that -Weverything enables.
add_compile_options(
-Weverything
-Wno-c++98-compat
-Wno-c++98-compat-pedantic
# FIXME: Suppress (just) in Boost header, and just with Clang/MSVC
# (regular Clang, and also the MSVC compiler, don't need them).
#-Wno-comma
#-Wno-deprecated
#-Wno-documentation
#-Wno-float-conversion
#-Wno-float-equal
#-Wno-missing-noreturn
#-Wno-old-style-cast
#-Wno-sign-conversion
#-Wno-reserved-id-macro
#-Wno-undef
#-Wno-zero-as-null-pointer-constant
)
elseif(MSVC)
# cl but not clang-cl accepts /Za to reject Microsoft extensions.
add_compile_options(/Za)
# cl but not clang-cl accepts /analyze for static analysis (default rules).
add_compile_options(/analyze)
else()
# Enable most warnings.
add_compile_options(-Wall -Wextra)
endif()
find_package(Boost REQUIRED)
add_executable(recursive-lambda-stdfunction
recursive-lambda-stdfunction.cpp
)
add_executable(recursive-lambda-combinatory
recursive-lambda-combinatory.cpp
)
add_executable(recursive-lambda-combinatory-wrapped
recursive-lambda-combinatory-wrapped.cpp
)
target_link_libraries(recursive-lambda-stdfunction PRIVATE Boost::boost)
target_link_libraries(recursive-lambda-combinatory PRIVATE Boost::boost)
target_link_libraries(recursive-lambda-combinatory-wrapped PRIVATE Boost::boost)
set(CPACK_PROJECT_NAME ${PROJECT_NAME})
set(CPACK_PROJECT_VERSION ${PROJECT_VERSION})
include(CPack)
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
Func<int, BigInteger> fib = n => {
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
Func<dynamic, int, BigInteger> f = (me, k) => {
if (memo.TryGetValue(k, out var result)) return result;
result = me(me, k - 2) + me(me, k - 1);
memo.Add(k, result);
return result;
};
return f(f, n);
};
fib(10).Dump();
fib(1000).Dump();
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
Func<dynamic, int, BigInteger> fib = (me, n) => {
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
if (memo.TryGetValue(n, out var result)) return result;
result = me(me, n - 2) + me(me, n - 1);
memo.Add(n, result);
return result;
};
fib(fib, 10).Dump();
fib(fib, 1000).Dump();
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
Func<int, BigInteger> fib = n => {
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
Func<dynamic, int, BigInteger> f = (me, k) => {
if (memo.TryGetValue(k, out var result)) return result;
var me_casted = (Func<object, int, BigInteger>)me;
result = me_casted(me, k - 2) + me_casted(me, k - 1);
memo.Add(k, result);
return result;
};
return f(f, n);
};
fib(10).Dump();
fib(1000).Dump();
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
Func<object, int, BigInteger> fib = (me, n) => {
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
if (memo.TryGetValue(n, out var result)) return result;
var me_casted = (Func<object, int, BigInteger>)me;
result = me_casted(me, n - 2) + me_casted(me, n - 1);
memo.Add(n, result);
return result;
};
fib(fib, 10).Dump();
fib(fib, 1000).Dump();
import java.math.BigInteger;
import java.util.HashMap;
import java.util.function.BiFunction;
import java.util.function.IntFunction;
final class LambdaCombinatoryFibonacciWrapped {
public static void main(String[] args) {
var memo = new HashMap<Integer, BigInteger>();
memo.put(0, BigInteger.ZERO);
memo.put(1, BigInteger.ONE);
IntFunction<BigInteger> fib = n -> {
if (n < 0)
throw new IllegalArgumentException("n must be nonnegative");
BiFunction<Object, Integer, BigInteger> f = (me, k) -> {
var result = memo.getOrDefault(k, null);
if (result != null) return result;
@SuppressWarnings("unchecked")
var me_casted = (BiFunction<Object, Integer, BigInteger>)me;
result = me_casted.apply(me, k - 2).add(me_casted.apply(me, k - 1));
memo.put(k, result);
return result;
};
return f.apply(f, n);
};
System.out.println(fib.apply(10));
System.out.println(fib.apply(1000));
}
}
import java.math.BigInteger;
import java.util.HashMap;
import java.util.function.BiFunction;
final class LambdaCombinatoryFibonacci {
public static void main(String[] args) {
var memo = new HashMap<Integer, BigInteger>();
memo.put(0, BigInteger.ZERO);
memo.put(1, BigInteger.ONE);
BiFunction<Object, Integer, BigInteger> fib = (me, n) -> {
if (n < 0)
throw new IllegalArgumentException("n must be nonnegative");
var result = memo.getOrDefault(n, null);
if (result != null) return result;
@SuppressWarnings("unchecked")
var me_casted = (BiFunction<Object, Integer, BigInteger>)me;
result = me_casted.apply(me, n - 2).add(me_casted.apply(me, n - 1));
memo.put(n, result);
return result;
};
System.out.println(fib.apply(fib, 10));
System.out.println(fib.apply(fib, 1000));
}
}
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
Func<int, BigInteger> fib = null!;
fib = n => {
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
if (memo.TryGetValue(n, out var result)) return result;
result = fib(n - 2) + fib(n - 1);
memo.Add(n, result);
return result;
};
fib(10).Dump();
fib(1000).Dump();
<Query Kind="Statements">
<Namespace>System.Numerics</Namespace>
</Query>
var memo = new Dictionary<int, BigInteger> { {0, 0}, {1, 1} };
BigInteger Fib(int n)
{
if (n < 0) throw new ArgumentOutOfRangeException(paramName: nameof(n));
if (memo.TryGetValue(n, out var result)) return result;
result = Fib(n - 2) + Fib(n - 1);
memo.Add(n, result);
return result;
}
Fib(10).Dump();
Fib(1000).Dump();
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <boost/multiprecision/cpp_int.hpp>
int main()
{
using boost::multiprecision::cpp_int;
std::unordered_map<unsigned, cpp_int> memo {{0, 0}, {1, 1}};
auto fib = [&memo](unsigned n) {
auto f = [&memo](const auto& me, unsigned k) {
if (auto p = memo.find(k); p != end(memo)) return p->second;
cpp_int result = me(me, k - 2) + me(me, k - 1);
memo.emplace(k, result);
return result;
};
return f(f, n);
};
std::cout << fib(10) << '\n';
std::cout << fib(1000) << '\n';
}
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <boost/multiprecision/cpp_int.hpp>
int main()
{
using boost::multiprecision::cpp_int;
std::unordered_map<unsigned, cpp_int> memo {{0, 0}, {1, 1}};
auto fib = [&memo](const auto& me, unsigned n) {
if (auto p = memo.find(n); p != end(memo)) return p->second;
cpp_int result = me(me, n - 2) + me(me, n - 1);
memo.emplace(n, result);
return result;
};
std::cout << fib(fib, 10) << '\n';
std::cout << fib(fib, 1000) << '\n';
}
#include <functional>
#include <iostream>
#include <iterator>
#include <unordered_map>
#include <boost/multiprecision/cpp_int.hpp>
int main()
{
using boost::multiprecision::cpp_int;
std::unordered_map<unsigned, cpp_int> memo {{0, 0}, {1, 1}};
std::function<cpp_int(unsigned)> fib = [&memo, &fib](unsigned n) {
if (auto p = memo.find(n); p != end(memo)) return p->second;
cpp_int result = fib(n - 2) + fib(n - 1);
memo.emplace(n, result);
return result;
};
std::cout << fib(10) << '\n';
std::cout << fib(1000) << '\n';
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment