Skip to content

Instantly share code, notes, and snippets.

Created May 28, 2012 15:04
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save anonymous/2819627 to your computer and use it in GitHub Desktop.
Save anonymous/2819627 to your computer and use it in GitHub Desktop.
#include <memory>
#include <iostream>
#include <string>
namespace lazy
{
template <class T> class Lazy
{
protected:
bool computed = false;
T value;
virtual void computeValue() = 0;
public:
virtual ~Lazy() {}
bool isComputed()
{
return computed;
}
T operator*()
{
return (*this)();
}
T operator()()
{
if(computed)
return value;
computeValue();
std::cout << "computed" << std::endl;
computed = true;
return value;
}
};
template <class T> class Just : public Lazy<T>
{
public:
Just(const T &a) { Lazy<T>::value = a; }
void computeValue() {}
};
template <class T> std::shared_ptr<Lazy<T>> just(T t)
{
return std::shared_ptr<Just<T>>(new Just<T>(t));
}
#define Operator(Name, name, op) \
template <class A, class B, class T> class Name : public Lazy<T> \
{ \
protected: \
std::shared_ptr<Lazy<A>> a; \
std::shared_ptr<Lazy<B>> b; \
void computeValue() \
{ \
Lazy<T>::value = (*a)() op (*b)(); \
a.reset(); \
b.reset(); \
} \
public: \
Name(std::shared_ptr<Lazy<A>> a, std::shared_ptr<Lazy<B>> b) : a(a), b(b) {} \
}; \
template <class A, class B> auto name(std::shared_ptr<Lazy<A>> a, std::shared_ptr<Lazy<B>> b) -> \
std::shared_ptr<Lazy<decltype((*a)() op (*b)())>> \
{ \
return std::shared_ptr<Lazy<decltype((*a)() op (*b)())>>(\
new Name<A, B, decltype((*a)() op (*b)())>(a, b)); \
}
Operator(Plus, operator+, +)
Operator(Star, operator*, *)
Operator(Minus, operator-, -)
Operator(And, operator&, &)
Operator(Or, operator|, |)
Operator(LogicalAnd, operator&&, &&)
Operator(LogicalOr, operator||, ||)
template <class A0, class B, class F> class Apply1 : public Lazy<B>
{
protected:
A0 a0;
std::shared_ptr<Lazy<F>> f;
void computeValue()
{
Lazy<B>::value = ((*f)())(a0);
f.reset();
}
public:
Apply1(std::shared_ptr<Lazy<F>> f, A0 a0)
{
this->f = f;
this->a0 = a0;
}
};
template <class F, class A0>
auto apply1(std::shared_ptr<Lazy<F>> f, A0 a0)
-> std::shared_ptr<Lazy<decltype(((*f)())(a0))>>
{
return std::shared_ptr<Lazy<decltype(((*f)())(a0))>> (
new Apply1<A0, decltype(((*f)())(a0)), F>(f, a0)
);
}
template <class R, class A0>
class Function1
{
std::shared_ptr<Lazy<std::function<R(A0)>>> f;
public:
Function1(std::shared_ptr<Lazy<std::function<R(A0)>>> f) : f(f)
{
}
std::shared_ptr<Lazy<R>> operator()(A0 a0)
{
return apply1(f, a0);
}
};
template <class R, class A0>
Function1<R, A0> function1(std::shared_ptr<Lazy<std::function<R(A0)>>> f)
{
return Function1<R, A0>(f);
}
#define FUNCTION1(R, A0, Body) \
function1(lazy::just( \
std::function<R(std::shared_ptr<lazy::Lazy<A0>>)> \
([] (std::shared_ptr<lazy::Lazy<A0>> i) Body ) \
))
class List;
class List : public std::pair<std::shared_ptr<Lazy<int>>, std::shared_ptr<Lazy<List>>> {
public:
List()
{ }
List(std::shared_ptr<Lazy<int>> a, std::shared_ptr<Lazy<List>> b) :
std::pair<std::shared_ptr<Lazy<int>>, std::shared_ptr<Lazy<List>>>(a, b)
{ }
List(const List &a) :
std::pair<std::shared_ptr<Lazy<int>>, std::shared_ptr<Lazy<List>>>(a)
{ }
};
}
void test1()
{
/* -- haskell analogue:
a = 20
b = 30
plusOne a = a + 1
c = plusOne $ a * b
main = print "..." >> print c
*/
auto a = lazy::just(20);
auto b = lazy::just(30);
auto plusOne = FUNCTION1(int, int, { return **i + 1; } );
auto c = plusOne(a*b);
std::cout << "..." << std::endl;
std::cout << **c << std::endl;
}
void test2()
{
/* -- haskell analogue:
a = 1
mkList a = a : mkList (a+1)
l = mkList a
main = print "..." >> (print $ head $ tail l)
*/
auto a = lazy::just(1);
lazy::Function1< lazy::List, std::shared_ptr<lazy::Lazy<int>> > mkList =
lazy::Function1< lazy::List, std::shared_ptr<lazy::Lazy<int>> > ( lazy::just(
(std::function<lazy::List( std::shared_ptr<lazy::Lazy<int>> )>)
([&mkList] (std::shared_ptr<lazy::Lazy<int>> a) {
return lazy::List(a, mkList(a + lazy::just(1)) );
})
));
auto l = mkList(a);
std::cout << "..." << std::endl;
std::cout << **((**((**l).second)).first) << std::endl;
}
int main()
{
std::cout << "test1" << std::endl;
test1();
std::cout << std::endl << "test2" << std::endl;
test2();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment