2012-09-27

SCIP in C++11 ― 3.1.3節


銀行口座その3:共同口座と問題3.7

3.1.1で、各銀行口座のbalanceオブジェクトをどのように保持しているのか、
C++11でもSchemeでも見づらくて気持ち悪い、という経験をしたが、
たしかにそれはバグの温床だわな。
普段のプログラムでも、オブジェクトをコロコロ変更すると訳がわからなくなるので、
なるべく一度インスタンス化したオブジェクトは変えないようなスタイルを、
なんとなく意識していたが、それが正しいのだ、ということ。

ただ、そうできたのは、そうできる問題に対することが多かったから、
ということにすぎない。データベースとか扱ったときはだいぶ混乱したこともある。
その辺をどう頑健にしていくかが3章の一つのテーマなのかな。

問題3.8Schemeの話なのでパス。

----
const function<List(List)> returnErrorMessage
=[](const List& Dummy){
    return(makeLeaf("Incorrect password"));
};

const function<List(List)> returnErrorMonitored
(makeMonitored(makeLeaf(returnErrorMessage)));

const function<List(List)> callTheCops
=[](const List& Dummy){
    return(makeLeaf("The cops are called."));
};

const function<List(List)> processError(const List& limitCount)
{
    if(returnErrorMonitored
       (makeLeaf("how-many-calls?"))>=limitCount-makeLeaf(1))
     {return(callTheCops);}
    return(returnErrorMonitored);
}

const function<function<List(List)>(List,List)> makeAccount
(const List& balanceIn, const List& passwdIn)
{

    const List&& balance(std::move(balanceIn));
    const List&& passwd(std::move(passwdIn));
    const List limitCount(makeLeaf(7));

    const function<List(List)> withdraw
     =[balance](const List& amount){
     if(balance>=amount){
         setInsert(balance-amount,balance);
         return(balance);
     }
     return(makeLeaf("Insuffcient funds"));
    };
   
    const function<List(List)> deposit
     =[balance](const List& amount){
     setInsert(balance+amount,balance);
     return(balance);
    };

    const function<function<List(List)>(void)> processErrorMessage
     =[limitCount](void){
     return(processError(limitCount));
    };

    const function<function<List(List)>(List,List)> dispatch=
     [withdraw,deposit,processErrorMessage,passwd,limitCount]
     (const List& passwdInput, const List& message){
     if(isEq(message,makeLeaf("error"))
        ||!isEq(passwd,passwdInput)){return(processErrorMessage());}
     returnErrorMonitored(makeLeaf("reset-count"));
     if(isEq(message,makeLeaf("withdraw"))){return(withdraw);}
     if(isEq(message,makeLeaf("deposit"))){return(deposit);}
     cerr<<"Unknown request --- MAKE-ACCOUNT"<<endl;
     exit(1);
     return(function<List(List)>([](const List& i){return(makeList());}));
    };
    return(dispatch);
}

const function<function<List(List)>(List,List)> makeJoint
(const function<function<List(List)>(List,List)>& oldAccountIn,
 const List& oldPasswdIn, const List& jointAccountPasswdIn)
{
    const function<function<List(List)>(List,List)>&&
     oldAccount(std::move(oldAccountIn));
    const List&& oldPasswd(std::move(oldPasswdIn));
    const List&& jointAccountPasswd(std::move(jointAccountPasswdIn));

    const function<function<List(List)>(List,List)> dispatch
     =[oldAccount,oldPasswd,jointAccountPasswd]
     (const List& passwdInput, const List& message){
     if(!isEq(jointAccountPasswd,passwdInput)){
         return(oldAccount(makeLeaf(""),makeLeaf("error")));
     }
     return(oldAccount(oldPasswd,message));
    };
    return(dispatch);
}

int main(int argc, char** argv)
{
    cout<<"Excersize 3.7:"<<endl;
    const auto peterAccount
     (makeAccount(makeLeaf(100),makeLeaf("open-sesame")));
    cout<<"peter-acc = (make-account 100 'open-sesame)"<<endl;
    cout<<"((peter-acc 'open-sesame 'withdraw) 40) = "
     <<listString(peterAccount
                  (makeLeaf("open-sesame"),
                   makeLeaf("withdraw"))(makeLeaf(40)))<<endl;
    cout<<"((peter-acc 'hirake-goma 'deposit) 40) = "
     <<listString(peterAccount
                  (makeLeaf("hirake-goma"),
                   makeLeaf("deposit"))(makeLeaf(40)))<<endl;
   
    const auto paulAccount
     (makeJoint(peterAccount,
                makeLeaf("open-sesame"),makeLeaf("rosebud")));
    cout<<endl<<"paul-acc = (make-joint peter-acc 'open-sesame 'rosebud)"<<endl;
    cout<<"((paul-acc 'rosebud 'withdraw) 40) = "
     <<listString(paulAccount
                  (makeLeaf("rosebud"),
                   makeLeaf("withdraw"))(makeLeaf(40)))<<endl;
    cout<<"((paul-acc 'open-sesame 'deposit) 40) = "
     <<listString(paulAccount
                  (makeLeaf("open-sesame"),
                   makeLeaf("deposit"))(makeLeaf(40)))<<endl;
    cout<<"((paul-acc 'rosebud 'deposit) 100) = "
     <<listString(paulAccount
                  (makeLeaf("rosebud"),
                   makeLeaf("deposit"))(makeLeaf(100)))<<endl;
    cout<<"((peter-acc 'open-sesame 'deposit) 40) = "
     <<listString(peterAccount
                  (makeLeaf("open-sesame"),
                   makeLeaf("deposit"))(makeLeaf(40)))<<endl;

    return(0);
}
----
出力
----
Excersize 3.7:
peter-acc = (make-account 100 'open-sesame)
((peter-acc 'open-sesame 'withdraw) 40) = 60
((peter-acc 'hirake-goma 'deposit) 40) = Incorrect password

paul-acc = (make-joint peter-acc 'open-sesame 'rosebud)
((paul-acc 'rosebud 'withdraw) 40) = 20
((paul-acc 'open-sesame 'deposit) 40) = Incorrect password
((paul-acc 'rosebud 'deposit) 100) = 120
((peter-acc 'open-sesame 'deposit) 40) = 160

SCIP in C++11 ― 3.1.2節


モンテカルロシミュレーションと問題3.5

まあこの問題でrandom-in-rangeを自前のListを使った実装にする意味は無い、
というかパフォーマンスがとても悪いし、
この辺のコードは、この本の後のほうで確か使わなかったと思うが、
一応set!の練習を兼ねて、Listを使った実装で。

問題3.6はメッセージパッシングの練習ではあるのだが、
このC++11Mersenne-twister乱数の実装ではあまり意味が無いのでパス。

----
const List randomUpdate(const List& dummy)
{
    std::random_device rd;
    std::mt19937 x(rd());
    std::uniform_int_distribution<> dis(1,1000);
    return(makeLeaf(dis(x)));
}

const function<List(void)> randSICP(void)
{
    const List x(makeLeaf(0));
    return([x](void){
         setInsert(x,randomUpdate(x));
         return(x);
     });
}

const List randomInRange(const List& low, const List& high)
{
    std::random_device rd;
    std::mt19937 gen(rd());
    std::uniform_real_distribution<> dis
     (value<double>(low), value<double>(high));
    return(makeLeaf(dis(gen)));
}



//---------abstraction barrier---------
const List gcd(const List& n1, const List& n2)
{
    if(n2==makeLeaf(0)){return(n1);}
    return(gcd(n2,n1%n2));
}


const double MonteCarlo
(const int trials, const function<bool(void)> experiment)
{
    function<double(int,int)> iter;
    iter=[&iter,trials,&experiment]
     (const int trialsRemaining,
      const int trialsPassed)
     {
         if(trialsRemaining==0){
             return(static_cast<double>(trialsPassed)
                    /static_cast<double>(trials));
         }
         if(experiment()){
             return(iter(trialsRemaining-1,trialsPassed+1));
         }
         return(iter(trialsRemaining-1,trialsPassed));
     };
    return(iter(trials,0));
}

const function<bool(void)> cesaroTest
=[](void){
    return(gcd(randSICP()(),randSICP()())==makeLeaf(1));
};

const double estimatePi(const int trials)
{
    return(sqrt(6.0
             /MonteCarlo(trials,cesaroTest)));
}

const function<bool(double,double,double,double)>
integralTest
(const function<double(double)>& f)
{
    return([f](const double x1,const double x2,
            const double y1,const double y2){
            const double x
                (value<double>
                 (randomInRange(makeLeaf(x1),makeLeaf(x2))));
            const double y
                (value<double>
                 (randomInRange(makeLeaf(y1),makeLeaf(y2))));
            return(f(x)>y);});
}


const double estimateIntegral
(const function<bool(double,double,double,double)>& P,
 const double x1,const double x2, const double y1,const double y2,
 const int trials)
{
    const function<bool(void)> predicateIntegration
     =[P,x1,x2,y1,y2](void){
     return(P(x1,x2,y1,y2));
    };
    return(MonteCarlo(trials,predicateIntegration));
}



int main(int argc, char** argv)
{
    cout<<"(estimate-pi 10000) = "<<estimatePi(10000)<<endl;
   
    cout<<endl<<"Excersize 3.5:"<<endl;
    const function<double(double)> circleFunc
     =[](const double x){return(std::sqrt(1.0-square(x)));};
    cout<<4.0*estimateIntegral
     (integralTest(circleFunc),
      0.0,1.0,0.0,1.0,10000)<<endl;

    return(0);
}
----
出力
----
(estimate-pi 10000) = 3.12729

Excersize 3.5:
3.1256

2012-09-26

SCIP in C++11 ― 3.1.1節その3


銀行口座その2:口座のパスワード保護と問題3.33.4

make-monitoredを問題3.2でしっかり作っておけば簡単。

----
const function<function<List(List)>(string,List)> makeAccount
(const List& balanceIn, const List& passwdIn)
{

    const List&& balance(std::move(balanceIn));
    const List&& passwd(std::move(passwdIn));
    const List limitCount(makeLeaf(7));

    const function<List(List)> withdraw
     =[balance](const List& amount){
     if(balance>=amount){
         setInsert(balance-amount,balance);
         return(balance);
     }
     return(makeLeaf("Insuffcient funds"));
    };
   
    const function<List(List)> deposit
     =[balance](const List& amount){
     setInsert(balance+amount,balance);
     return(balance);
    };
   
    const function<List(List)> returnErrorMessage
     =[](const List& Dummy){
     return(makeLeaf("Incorrect password"));
    };

    const function<List(List)> returnErrorMonitored
     (makeMonitored(makeLeaf(returnErrorMessage)));

    const function<List(List)> callTheCops
     =[](const List& Dummy){
     return(makeLeaf("The cops are called."));
    };

    const function<function<List(List)>(string,List)> dispatch=
     [withdraw,deposit,returnErrorMonitored,passwd,limitCount,callTheCops]
     (const string passwdInput, const List& message){
     if(!isEq(passwd,makeLeaf(passwdInput))){
         if(returnErrorMonitored
            (makeLeaf("how-many-calls?"))>=limitCount-makeLeaf(1))
             {return(callTheCops);}
         return(returnErrorMonitored);
     }
     returnErrorMonitored(makeLeaf("reset-count"));
     if(isEq(message,makeLeaf("withdraw"))){return(withdraw);}
     if(isEq(message,makeLeaf("deposit"))){return(deposit);}
     cerr<<"Unknown request --- MAKE-ACCOUNT"<<endl;
     exit(1);
     return(function<List(List)>([](const List& i){return(makeList());}));
    };
    return(dispatch);
}



int main(int argc, char** argv)
{
    cout<<"Excersize 3.3:"<<endl;
    const auto acc(makeAccount(makeLeaf(100),makeLeaf("secret-password")));
    cout<<"((acc 'secret-password 'withdraw) 40) = "
     <<listString(acc(string("secret-password"),
                      makeLeaf("withdraw"))(makeLeaf(40)))<<endl;
    cout<<"((acc 'some-other-password 'deposit) 40) = "
     <<listString(acc(string("some-other-password"),
                      makeLeaf("deposit"))(makeLeaf(40)))<<endl;

    cout<<endl<<"Excersize 3.4:"<<endl;
    cout<<"((acc 'secret-password 'withdraw) 40) = "
     <<listString(acc(string("secret-password"),
                      makeLeaf("withdraw"))(makeLeaf(40)))<<endl;
    for(int i=0;i<8;++i){
     cout<<"((acc 'some-other-password 'deposit) 40) = "
         <<listString(acc(string("some-other-password"),
                          makeLeaf("deposit"))(makeLeaf(40)))<<endl;
    }
    cout<<"((acc 'secret-password 'deposit) 40) = "
     <<listString(acc(string("secret-password"),
                      makeLeaf("deposit"))(makeLeaf(40)))<<endl;
    cout<<"((acc 'some-other-password 'deposit) 40) = "
         <<listString(acc(string("some-other-password"),
                          makeLeaf("deposit"))(makeLeaf(40)))<<endl;
   

    return(0);
}
----
出力
----
Excersize 3.3:
((acc 'secret-password 'withdraw) 40) = 60
((acc 'some-other-password 'deposit) 40) = Incorrect password

Excersize 3.4:
((acc 'secret-password 'withdraw) 40) = 20
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = Incorrect password
((acc 'some-other-password 'deposit) 40) = The cops are called.
((acc 'some-other-password 'deposit) 40) = The cops are called.
((acc 'secret-password 'deposit) 40) = 60
((acc 'some-other-password 'deposit) 40) = Incorrect password