Pages

About Me - 关于我

My photo
Madison, WI, United States
Joy Young ~~

2012/07/21

Y-combinator in C++

YCombinator serves as an important role in lamda calculas. I was not interested in it until C++ introduced lamda function as a new feature in C++ 11. Then C++ is facing a same critical issue that rises in lamda calculas: As a lamda function is nameless, how could we write a recursive lamda function?
In lamda calculas, it is extremly difficult. The research on this topic results in the birth of Y-combinator, which is one of the most beatiful operator in mathematics and MIT math department adpot it as its department elblem. Y-combinator can convert a non-recursive version of a function into a recursive one. I was wondering if it is possible to implement Y-combinator in C++. Unfortuately, a real Y-combinator is not possible, because in lamda calculas, the Y combinator cant be recursive either. But, inspired by a post on stack overflow, we can relax this restriction: why can't we simply write a Y combinator in a recursive way in C++. I finally got a solution to it:
The following code must run with C++11 support.


//inspired by & referencing a post on stack overflow
#include <functional>
#include <iostream>
using namespace std;
template<class ArgType, class RetType>
function<RetType(ArgType)> YCombinator(function<RetType(function<RetType(ArgType)>, ArgType)> pseudo_recur_func)
{
  return bind(pseudo_recur_func, bind(&YCombinator<ArgType, RetType>, pseudo_recur_func), placeholders::_1);
}

int main()
{

       //pass a pseudo-recursive lambda function (in the sense that the 'self' argument is actually not itself)
      //to Y Combinator, which returns an equivalent real-recusive function of lambda.
       auto fibonacci = YCombinator<int, int>(
              [](function<int(int)> self , int n){return n <= 1 ? 1 : self(n - 2) + self(n - 1);}//this is the pseudo recusive lambda
              );
       //test 0~9
       for(int i = 0; i < 10; ++i)
              cout<<fibonacci(i)<<ends;
       return 0;
}

2011/10/30

一个人最宝贵的六样东西

一个人最宝贵的东西是什么。很早就想过这个问题,事业?亲人?幸福?安全?自己的答案一直感觉并不是很贴切。第一次听到一个很让我信服的答案是大二那年和tx聊天,她也曾思考过这个问题,她说,是 爱,希望,和健康。
这个答案曾让我眼前一亮,那晚和她在北师散步了许久,便也把这个问题聊的通透蹭亮。甚至排了一个顺序,爱>希望>健康。本以为这便是最终的答案,然而多年以后,我竟然突然又无端的想起了这个问题。
tx无疑是正确的,但也许还有更多。
tx的答案可以作为一个基础,后来我便由此发散而去。
若是将我禁闭于某囚牢,失去自由,我宁可断腿,来换回自由。但若是有爱,和所爱且爱我的人一起,那便也没什么。若我有希望,相信有朝一日,我能重归自由,那也没有什么。所以自由,也应该排进去的,现在是爱>希望>自由>健康
还漏了什么。生命诚可贵,爱情价更高。确实,若是众叛亲离,无人爱,那不如死了。若是整日郁郁,失去希望,活着也没有意义。若是禁闭于囚牢一世,但有希望有爱,活着也挺好。所以生命可以排进来,爱>希望>生命>自由>健康。
还有什么?以前在论坛上做过一个调查,问如果把你立刻变成比尔盖茨,你愿意么?几乎没人说愿意的, 因为即使他再成功,没人愿意跳过自己40年的青春去换他的功名利禄。可见年轻竟然如此的宝贵。不过,60岁的自由生活,和20岁的囚牢生活,相信更多人会宁可过60岁的自由生活。所以年轻小于自由。如果身体不健康,20岁的体质和剩的寿命还不如60岁,那宁可选60岁,所以健康应该和年轻差不多,略大一点。所以最后我们有:
爱>希望>生命>自由>健康>年轻
就先这么多吧。

人应该定期思考下人生,不可入世太深,迷失本心,不知本我,残度聊生。

2011/04/19

TheTricky Parts of Rvalue Reference and Perfect Forwarding.

I have read two articles about these stuffs. They are good. Here are the links:
I would not like to spend much time whenever I want to look up some useful information from these two articles, so I summarize something useful for my future reference.

1. Rvalue reference is not rvalue but reference
If you try to change the value of rvalue reference, it affects the value of the object it is referencing.

2. move semantic is awesome, but not irreplaceable.

Alternatively, you can use the static_cast keyword to cast an lvalue to an rvalue reference, as shown in the following example:

int main()
{
       MemoryBlock block;
       g(block);
       g(static_cast<MemoryBlock&&>(block));//as good as move
}

3. The compiler treats a named rvalue reference as an lvalue and an unnamed rvalue 
reference as an rvalue.
void g(X&& t); // A
void g(X& t);      // B

void h(X&& t)
{
       g(t);
}

Though t is declared like rvalue reference, but it is named, so g() always treats t as lvalue. If we changed the call to g(std::move(t)) then it would always call the rvalue-reference overload.
 
4. What does std::forward do?
When T is an lvalue reference, std::forward<T> is a no-op: it just returns its argument. 
When we pass a temporary to f, so T is just plain X. In this case,  std::forward<T>(t) is equivalent to static_cast<T&&>(t): it ensures that the argument is forwarded as an rvalue reference
Note that, it does not have anything to do with t. How it works is related to T solely.
5. What does std::move do? 
 Based on my understanding alone, its function is nothing more than a static_cast<T&&>()
Here I found some evidence: 
template<typename T>
remove_reference<T>::type&& move(T&& a)
{
       return a;
}

By Jonathan Caves

Jonathan Caves - Visual C++ Compiler Team

remove_reference here is a class from boost, it removes the reference symbol & and add two more instead!

6.  Perfect forwarding is unique to template functions: we can't do this with a non-template function such as h.
To understand this, let’s see how the template deduce the parameters:
First of all, we need to write a template this way:
template <typename T> void print_type_and_value(T&& t)

The tricky part is the T&& in the function. According to different form of T, the T&& will generate different types. See:
int main()
{
      // The following call resolves to:
      // print_type_and_value<string&>(string& && t)
      // Which collapses to:
      // print_type_and_value<string&>(string& t)
      string s1("first");
      print_type_and_value(s1);

      // The following call resolves to:
      // print_type_and_value<const string&>(const string& && t)
      // Which collapses to:
      // print_type_and_value<const string&>(const string& t)
      const string s2("second");
      print_type_and_value(s2);

      // The following call resolves to:
      // print_type_and_value<string&&>(string&& t)
      print_type_and_value(string("third"));

      // The following call resolves to:
      // print_type_and_value<const string&&>(const string&& t)
      print_type_and_value(fourth());
}

The deduction rule:


Expanded type
Collapsed type
T& &
T&
T& &&
T&
T&& &
T&
T&& &&
T&&

Now let’s go back to the discussion of trying perfect forwarding in non-template function:
Within a function that takes its arguments as rvalue references, the named parameter is treated as an lvalue reference. Consequently the call to g(t) from h always calls the lvalue overload. If we changed the call to g(std::forward<X>(t)) then it would always call the rvalue-reference overload. The only way to do this with "normal" functions is to create two overloads: one for lvalues and one for rvalues.
Finally, I attached this piece of code for quick testing.

#include <iostream>
using namespace std;
struct X{int i;};
void g(X&& t){ t.i = -1; cout<<"&&"<<endl;}; // A
void g(X& t){ t.i = -2; cout<<"&"<<endl;}      // B

template<typename T>
void f(T&& t){    g(std::forward<T>(t));}
void h1(X&& t){   g(t);}
void h2(X& t){    g(std::forward<X>(t));}
void h3(X& t){    g(std::forward<X&>(t));}
void h4(X& t){    g(std::move(t));}

int main()
{
     
      X x;
      x.i = 0;
      f(x);   // 1
      f(X()); // 2
      h1(X()); // 3
      h2(x); // 3
      cout<<x.i<<endl;
      h3(x);
      cout<<x.i<<endl;
      h4(x);
      cout<<x.i<<endl;
      getchar();
}










2011/04/06

C++嵌套类

1  1. 嵌套类的名字只在外围类可见。
  2. 类的私有成员只有类的成员和友元可以访问,因此外围类不可以访问嵌套类的私有成员。嵌套类可以访问外围类的成员(通过对象、指针或者引用)。
  3.一个好的嵌套类设计:嵌套类应该设成私有。嵌套类的成员和方法可以设为 public
    4.嵌套类可以直接访问外围类的静态成员、类型名( typedef )、枚举值。
   5. 嵌套类定义的名字解析过程:
出现在名字使用点前的嵌套类的声明。
出现在名字使用点前外围类的声明。
嵌套类定义前名字空间域的声明。

 

66. 嵌套类的成员定义中的名字解析过程:
成员函数局部声明。
嵌套类成员的声明。
外围类成员的声明。
成员函数定义前名字空间域中出现的声明。

2011/04/03

哎,又想骑车去旅行了


我很懒,但是有颗不安分的心。我想过着慵懒的生活,却又不甘平凡。
保研前,一直想保研,当真发现自己能保研了,却又觉着无趣了,然后准备出国,有病是不?
懒的运动,篮球足球都不爱,因为运动量太大,太累,结果大二花了十天灰头土脸的从北京骑车600多公里回了趟家,有病是不?
美国的生活很麻烦,各种事情,各种不顺,压力很大,也没时间。自己每天回家就累的啥也不想干了,但是,突然又想骑车旅行了。
非运动型人士,骑车旅行对我来说,本应更像一个概念而非实践。不过一件事,虽然笨了点,慢了点,但只要决定去做,总还是能做成的。
上次骑了650公里。这次,如果有可能,想骑个夸张的,从东海岸骑到西海岸去。初步估计,有4500公里。以我的运动能力,大概需要40多天,才能完成。太不切实际了是么?我也觉着有点,但是,如果拿定主意去做,其实不难。我需要的仅仅是:
1.  1. 1个半月的假期
2.  2. 一两位同伴
3.  3. 10000美金
其他的,就是周详的计划,调查,问询。上回十天的旅行,做了15天计划。这回40天的旅程,也要做2个月调查计划吧。也许老美和中国不太一样,比如没自行车道,比如中部无旅馆,有野兽,但这些都不会构成根本威胁。必须的仅仅是之上3条。
哈,大学那次,从有构想,但遇到志同道合之人,到付诸实施,过了两年吧。这个构想,不知道什么时候能实现,今天就放这里了,希望34年后的某天,我会再次出发。