<?xml version="1.0" encoding="UTF-8"?><rss xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom" version="2.0" xmlns:media="http://search.yahoo.com/mrss/"><channel><title><![CDATA[FreedomKnight's Blog]]></title><description><![CDATA[熱血的衝一發吧]]></description><link>https://fk.wtf/</link><image><url>http://fk.wtf/favicon.png</url><title>FreedomKnight&apos;s Blog</title><link>https://fk.wtf/</link></image><generator>Ghost 2.1</generator><lastBuildDate>Sun, 19 Apr 2026 12:16:53 GMT</lastBuildDate><atom:link href="https://fk.wtf/rss/" rel="self" type="application/rss+xml"/><ttl>60</ttl><item><title><![CDATA[Coroutine, Generator 那是什麼？]]></title><description><![CDATA[<p>在談到 coroutine 之前，先來看一下緣起好了</p>
<h2 id="">異步</h2>
<p>在現在的程式語言中，一直都有想做到異步、平行的需求，以減少 CPU 停下來等 IO 的時間。</p>
<p>目前有的解決方案，如 javascript 是直接對於會遇到 io 的程式碼直接跳過不執行，等到程式有空去執行 IO 的部分才會去處理。</p>
<p>例如：</p>
<pre><code class="language-js">var fs = require('fs');

fs.readFile(function (file) {
    console.log('world');
});

console.log('hello');
</code></pre>
<p>以上述的例子來說，當中的 <code>readFile</code> 是一個異步的函數，當下不會執行，只會將你寫的 callback 函數註冊起來，等到有空的時候再去呼叫你寫的 callback</p>
<p>因此上述 console.log</p>]]></description><link>https://fk.wtf/coroutine-generator-na-shi-shi-mo/</link><guid isPermaLink="false">5b916823a7dce77ebd3443f0</guid><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Fri, 08 Dec 2017 10:21:00 GMT</pubDate><content:encoded><![CDATA[<p>在談到 coroutine 之前，先來看一下緣起好了</p>
<h2 id="">異步</h2>
<p>在現在的程式語言中，一直都有想做到異步、平行的需求，以減少 CPU 停下來等 IO 的時間。</p>
<p>目前有的解決方案，如 javascript 是直接對於會遇到 io 的程式碼直接跳過不執行，等到程式有空去執行 IO 的部分才會去處理。</p>
<p>例如：</p>
<pre><code class="language-js">var fs = require('fs');

fs.readFile(function (file) {
    console.log('world');
});

console.log('hello');
</code></pre>
<p>以上述的例子來說，當中的 <code>readFile</code> 是一個異步的函數，當下不會執行，只會將你寫的 callback 函數註冊起來，等到有空的時候再去呼叫你寫的 callback</p>
<p>因此上述 console.log 的順序會是 ‘hello’, ‘world’</p>
<p>雖然執行順序跟閱讀的順序不一樣，但確實可以節省 CPU 等待 IO 的時間。這麼方便的東西，一般開發者其實無法寫出異步的函數，只能用系統提供的異步函數。</p>
<h2 id="coroutine">Coroutine</h2>
<p>前面  readFile 的例子，幾乎就只有系統提供的函數能變成異步的，要是使用者也想寫出這樣的東西在以往幾乎是不可行。而 php, python 等語言借鑒了其他語言中 coroutine 的概念，逐步實現了使用者自行撰寫異步函數的功能。</p>
<p>先列出要實現異步功能的需求：</p>
<ol>
<li>讓出函數的執行權</li>
<li>繼續執行未完成的部分</li>
</ol>
<p>而在其他有實現 coroutine 功能的語言裡面，多半以 <code>yield</code> 這樣的語法來讓出函數的執行權</p>
<p>例如 :</p>
<pre><code>function 自我感覺IO很吃重的函數($callback) {
     yield; // 這裡先讓出執行權，之後的程式碼等有空再執行
     print(&quot;start to read data&quot;);
     $data = do_somthing_io(); // 很吃重的工作
     $callback($data); // 取得資料後送給你註冊的 callback
}
</code></pre>
<p>上述的程式碼在第一次呼叫的時候什麼事都不會發生，因為 yield 這行就讓出執行權了。</p>
<p>但是 yield 跟 return 最大的不同點在於 yield 會紀錄函數執行到一半的狀態，你可以用某些語法繼續執行，以下以 resume 函數當作繼續執行的功能</p>
<pre><code>var $執行到一半的函數 = 自我感覺IO很吃重的函數();
print(&quot;hello&quot;);
resume($執行到一半的函數)
</code></pre>
<p>以上的範例是說明 自我感覺IO很吃重的函數() 會回傳一個執行到 yield 的紀錄，讓你可以用 consume 函數繼續執行它。</p>
<p>而上面的例子就是認為在 <code>print(“hello”)</code>  才有空去執行剩餘 IO 吃重的部分。</p>
<p>如果有螢幕的話，在螢幕上顯示文字的順序大概會是這樣 :</p>
<pre><code>hello
start to read data
</code></pre>
<p>基本所謂的 coroutine 大概是這樣，與前面 js 的 readFile 的差異在於繼續執行的時間點是由自己呼叫 consume() 去控制，而非系統自己找時間點去執行</p>
<p>附帶一提，這裡說明的 coroutine 還差了那麼一點點，真正的 coroutine 是可以指定 yield 之後可以跳到哪裡。但為了說明方便，這裡假定會跳回呼叫者處。</p>
<h2 id="generator">Generator 又是什麼</h2>
<p>提到 php, python 實作 coroutine 的時候一定又會提及 Generator</p>
<p>其實 Generator 是融合了 iterator 跟 coroutine 兩種特性的東西，在 php 裡面實作了 Iterator 介面，便能夠讓物件被 <code>foreach</code> 語法拿來迭代，類似這樣的物件便可以被稱作 iterator 迭代器。</p>
<p>在 php 裡面也是可以使用 yield 的，如果我們對一個函數 yield 去 var_dump 觀察一下可以發現會得到一個名為 Generator 的物件。</p>
<p>這個 Generator 其實也是前面提到的 <code>執行到一半的函式</code> 可以讓我們透過某種方法繼續執行下去。</p>
<p>而 php 的 Generator 是以實作了 Iterator 的作法，讓我們使用裡面的 next() 方法去執行下一步。</p>
<p>這樣融合迭代器的作法，又額外了多解決了一些記憶體消耗的情境。</p>
<p>以產生 1000 個奇數為例，會試做以下的函數 :</p>
<pre><code>function odds()
{
    $odds = [];
    for ($odd = 0; count($odds) &lt; 1000; $odd++) {
        if ($odd % 2 == 1)
            $odds[] = $odd;
    }

    return $odds;
</code></pre>
<p>在這裡會生成塞 1000 個奇數的陣列，當這個陣列小的時候還不會覺得有多大的問題。但是數量一多，然後可能要做的事情只是 print 出數字，整個記憶體就浪費了。</p>
<p>我們可以將上面例子稍微改寫一下</p>
<pre><code>function odds()
{
    for ($i = 0;; $i++) {
        if ($i % 2 == 1) {
            yield $i;
        }
    }
}
foreach (odds() as $i =&gt; $value) {
    if ($i == 1000) break;
    echo $value . &quot;\n&quot;;
}
</code></pre>
<p>這裡的 odds()  是用個無窮迴圈來產出所有奇數，但是根本不用怕會被無窮迴圈卡在這個函數裡，因為每產出一個奇數，便會讓出執行權。</p>
<p>而這裡有個小小的不同，就是在 yield 的後方可以加上類似回傳值的東西。在 Generator 裏可以利用 current() 方法把這個回傳值給取出來。如果是跑在 foreach 迴圈裡也不用想太多，迴圈會自己幫忙帶進來。</p>
<p>以這個改寫的例子來說，所佔用的記憶體只有一個變數 $i ，然後利用 coroutine 會記住上次執行狀態的特性，就能夠減少其他的記憶體消耗了。</p>
<p>最後稍微提一下，在 php 裡是不能夠自己去 new 一個 Generator 的唷，因為這個特殊的迭代器要記住當下的執行狀態，所以都是以 C 去寫成的，所以目前只能靠 yield 去產生 Generator 。</p>
]]></content:encoded></item><item><title><![CDATA[rsync 是如何比較檔案差異的？]]></title><description><![CDATA[<p>rsync 是 unix 上常常被用來同步兩臺主機資料的指令。而 rsync 令人稱道同步能力，不僅僅是把檔案抓下來到本機，而是厲害到可以只下載一個檔案中的差異部分，而非整份檔案抓下來。</p>
<p>如果自己想自製一個能夠比較兩份文件差異的程式，稍微想一下設計，大約還能以行爲單位來設計，找出差異。<br>
但是如果檔案並非純文字，而是像照片這般的二進位檔案，可能一整份檔案都沒有任何換行符號，一比較差異就是讓伺服器把整份檔案重新抓下來了。</p>
<p>面對通用檔案的差異比較，其設計思路就會朝向將檔案切成一塊一塊的區塊來進行差異比較。但終究需要面對以下問題：</p>
<ul>
<li>不可能將每個區塊的內容下載下來讓客戶端進行比較，這樣等同下載整份檔案</li>
<li>如果只是檔頭加了一點內容，切割區塊有機會造成每個區塊內容就不同，也等同要下載整份檔案</li>
</ul>
<p>面對以上問題，rsync 採用了一些不錯的解決對策</p>
<h4 id="checksum">校驗和 (Checksum)</h4>
<p>校驗和不是 rsync 獨有的東西，很早就有利用校驗和來檢查檔案是否完整的流程存在。而校驗和其原理就只是利用檔案內的資料產生一個獨特的值，讓下載方與供應方用同樣的方法生出該值，稍加比較就知道兩個檔案是否相同。</p>
<p>舉個最簡單的校驗和的例子，假設檔案內容如下：</p>
<pre><code>{5, 6, 7, 8}
</code></pre>
<p>最簡單的校驗和可以直接全部內容相加，其校驗和爲 26 ，只要下載方的校驗和也是 26 ，檔案下載完整的</p>]]></description><link>https://fk.wtf/rsync-shi-ru-he-bi-jiao-dang-an-chai-yi-de/</link><guid isPermaLink="false">5b9167d0a7dce77ebd3443ec</guid><category><![CDATA[rsync]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Fri, 15 Apr 2016 17:28:00 GMT</pubDate><content:encoded><![CDATA[<p>rsync 是 unix 上常常被用來同步兩臺主機資料的指令。而 rsync 令人稱道同步能力，不僅僅是把檔案抓下來到本機，而是厲害到可以只下載一個檔案中的差異部分，而非整份檔案抓下來。</p>
<p>如果自己想自製一個能夠比較兩份文件差異的程式，稍微想一下設計，大約還能以行爲單位來設計，找出差異。<br>
但是如果檔案並非純文字，而是像照片這般的二進位檔案，可能一整份檔案都沒有任何換行符號，一比較差異就是讓伺服器把整份檔案重新抓下來了。</p>
<p>面對通用檔案的差異比較，其設計思路就會朝向將檔案切成一塊一塊的區塊來進行差異比較。但終究需要面對以下問題：</p>
<ul>
<li>不可能將每個區塊的內容下載下來讓客戶端進行比較，這樣等同下載整份檔案</li>
<li>如果只是檔頭加了一點內容，切割區塊有機會造成每個區塊內容就不同，也等同要下載整份檔案</li>
</ul>
<p>面對以上問題，rsync 採用了一些不錯的解決對策</p>
<h4 id="checksum">校驗和 (Checksum)</h4>
<p>校驗和不是 rsync 獨有的東西，很早就有利用校驗和來檢查檔案是否完整的流程存在。而校驗和其原理就只是利用檔案內的資料產生一個獨特的值，讓下載方與供應方用同樣的方法生出該值，稍加比較就知道兩個檔案是否相同。</p>
<p>舉個最簡單的校驗和的例子，假設檔案內容如下：</p>
<pre><code>{5, 6, 7, 8}
</code></pre>
<p>最簡單的校驗和可以直接全部內容相加，其校驗和爲 26 ，只要下載方的校驗和也是 26 ，檔案下載完整的 <strong>可能性</strong> 就越高。</p>
<p>這裡的說明是用 <strong>可能性</strong> 是因為大家都知道直接相加的缺點。有太多可以產生相同校驗和的方法了。<br>
例如以下內容皆有機會被視為相同檔案：</p>
<pre><code>{3, 7, 8, 8}
{9, 2, 5, 11}
</code></pre>
<p>因此資訊界競相設計出各種校驗和的演算，例如 md4, md5 ，都宣稱高度可信，很難有不同的來源會產生相同的校驗和。但是越高度可信，所需要的計算時間越久，甚至需要產生一些質數出來輔助。</p>
<p>總結校驗和帶來的幫助，就是無需將伺服器上的每個區塊的內容都下載下來比較，只需要比較其校驗和便能得知是否有相同內容。</p>
<h4 id="rsync">rsync 策略概述</h4>
<p>rsync 接下來要面對的問題，就是如何避免檔案偏移，就造成下載整份檔案的狀況。其流程大概像下面的步驟：</p>
<ol>
<li>將伺服器上的檔案 B 切成不重疊的區塊。</li>
<li>將檔案 B 的所有區塊分別算出一個<strong>弱校驗和</strong>(Rolling Checksum) 和 <strong>強校驗和</strong> (md4)</li>
<li>客戶端將所有區塊的校驗和下載製表 (hash table)</li>
<li>客戶端從檔案 A 的檔頭開始切區塊，先只快速算出 <strong>弱校驗和</strong>，用其查表，查看是否存在</li>
<li>查表
<ul>
<li>若無法用弱校驗和查出檔案 B 有該區塊，則區塊往下偏移繼續切並重複步驟 4 直至檔尾。</li>
<li>若能查表查到才用<strong>強校驗和</strong>計算並比較，若符合代表有該區塊，並紀錄該區塊存在。反之則重複步驟 4</li>
</ul>
</li>
</ol>
<p>這個策略流程很簡單，但是要突破的瓶頸就是速度。不斷地將區塊偏移並且查詢比較非常耗時，因此其核心是快速的產生校驗和，快速的得知沒有相符的區塊，以避免每個區塊都用速度較慢的強校驗和檢查。在此 rsync 設計的 Rolling Checksum 佔了非常重要的位置。</p>
<p>而 Rolling Checksum 其速度跟前述的將所有資料相加的速度是一樣快的，但又沒有說弱到一下就產生碰撞 ，因此非常適合作初步檢驗。</p>
<h4 id="rollingchecksum">Rolling Checksum</h4>
<p>為了說明方便， Rolling Checksum 簡化算式如下</p>
<pre><code>i 是 block 的開始位置，j 爲結束位置
bsize 則是一個 block 的大小

A = block[i] + block[i+1] + ... + block[j] // 從頭加到尾的意思
B = bsize * block[i] + (bsize - 1) * block[i+1] + ... + 1 * block[j] 

rolling_checksum = A + B
</code></pre>
<p>假設一個 block 的大小爲 4 個 byte ， 且 block 內容依然是</p>
<pre><code>{5, 6, 7, 8}
</code></pre>
<p>其 Rolling Checksum 爲</p>
<pre><code> A = 5 + 6 + 7 + 8
 B = (4 * 5) + (3 * 6) + (2 * 7) + (1 * 8)
</code></pre>
<p>那為什麼說其速度跟全部加起來一樣快呢？ 觀察 A 部分的全部相加，大概會這樣設計一個迴圈</p>
<pre><code> A = 0;
 for (i = 0; i &lt; bsize; i++) {
     A += block[i];
 } 
</code></pre>
<p>將迴圈的流程稍微拆解一下，觀察一下 A 的內容</p>
<pre><code>1.) A = 5
2.) A = 5 + 6
3.) A = 5 + 6 + 7
4.) A = 5 + 6 + 7 + 8
</code></pre>
<p>可以發現當中的 5 出現了 4 次，6 出現了 3 次，竟然跟算式 B 的要求吻合（這當然是有設計過的呀）。<br>
所以要計算 B 的值只需要在同一個迴圈累加一下 A 便能同時算出 B 的值。稍微改寫如下</p>
<pre><code>A = 0, B = 0;
for (i = 0; i &lt; bsize; i++) {
    A += block[i]
    B += A;
}
</code></pre>
<p>最後補正為了說明而簡化的部分，其實這部分就只是為了 hash table 查詢所需要的取餘數的部分</p>
<p>完整定義：</p>
<pre><code>A = (block[i] + block[i+1] + ... + block[j]) % M // 從頭加到尾的意思
B = (bsize * block[i] + (bsize - 1) * block[i+1] + ... + 1 * block[j]) % M 

rolling_checksum = A + (2^16) * B</code></pre>
]]></content:encoded></item><item><title><![CDATA[annotation 的二三事]]></title><description><![CDATA[<h3 id="">第一次看這隻小老鼠</h3>
<p>在 java 裡面常常會看見下面這樣的用法</p>
<pre><code>@Override
void method() {
}
</code></pre>
<p>上面有個小老鼠的 <code>@Override</code> 便是 annotation 。<br>
這個 @Override 的作用是開發者繼承某個 class 之後，想要覆寫父類別的時候加上這個 annotation 可以讓編譯器知道你想覆寫，因此編譯器會檢查父類別是否有相同的 method ，以免你原本想要覆寫父類別的 method 結果卻手殘打錯字沒有真的覆寫到而發生意外。</p>
<p>因此 annotation 的作用就是讓被 annotation 標籤上的 class, method 之類的東西額外的增加資訊。</p>
<h3 id="">再看小老鼠</h3>
<p>一開始我也不知道這 annotation 到底有什麼用途，直到我看見 python 的幾個 web 框架有以下的做法</p>
<pre><code>@get('/index')
def getIndex():
    return &quot;&lt;p&</code></pre>]]></description><link>https://fk.wtf/annotation-de-er-san-shi/</link><guid isPermaLink="false">5b916778a7dce77ebd3443e6</guid><category><![CDATA[java]]></category><category><![CDATA[python]]></category><category><![CDATA[php]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Thu, 15 Oct 2015 13:34:00 GMT</pubDate><content:encoded><![CDATA[<h3 id="">第一次看這隻小老鼠</h3>
<p>在 java 裡面常常會看見下面這樣的用法</p>
<pre><code>@Override
void method() {
}
</code></pre>
<p>上面有個小老鼠的 <code>@Override</code> 便是 annotation 。<br>
這個 @Override 的作用是開發者繼承某個 class 之後，想要覆寫父類別的時候加上這個 annotation 可以讓編譯器知道你想覆寫，因此編譯器會檢查父類別是否有相同的 method ，以免你原本想要覆寫父類別的 method 結果卻手殘打錯字沒有真的覆寫到而發生意外。</p>
<p>因此 annotation 的作用就是讓被 annotation 標籤上的 class, method 之類的東西額外的增加資訊。</p>
<h3 id="">再看小老鼠</h3>
<p>一開始我也不知道這 annotation 到底有什麼用途，直到我看見 python 的幾個 web 框架有以下的做法</p>
<pre><code>@get('/index')
def getIndex():
    return &quot;&lt;p&gt; hello &lt;/p&gt;&quot;
</code></pre>
<p>這是個小小的 route ，說明的是如果使用者使用 GET 方法連線到 /index 這個網址，就使用被標籤的 method ，而這個被標籤的 method 會回傳一串 html 作為回應，這裡不必太過在意後面的行為。</p>
<h3 id="">小老鼠進化史</h3>
<p>從前面看來，發現似乎如此一來前面的 getIndex() 邏輯是很清晰的，而不會混雑著太長的設定路徑以及 http method 的邏輯，而是交由背景某個東西去運作，只需要使用 <code>@get('/index')</code> 這樣的標籤，就能讓背景的魔手去設定。</p>
<p>而這樣的概念爬了一下歷史，可以發現似乎是在 C 時代就會想使用 macro 去改變 function 的宣告，像是在 php 可以常常看到像是下面這樣的方法去宣告 function</p>
<pre><code>// hello.c
PHP_FUNCTION (hello) {
    // do something
}
</code></pre>
<p>而當中的 PHP_FUNCTION 是個 macro 會去將這整個文字內容改成符合自己要求的 function 結構，隨便瞎掰一個可能的例子，例如:</p>
<pre><code>// hello.c
php_function_ret *hello (int a, int b) {
    // do something
}
</code></pre>
<p>這樣可以將這段可重用的邏輯抽離出來並且隱藏又臭又長的 code ，而且如此一來還有一點點這是給 hello 這個 function 進行撰寫程式內的設定檔的概念</p>
<p>因此可以稍微整理出我們對此類的需求大概如下：</p>
<ul>
<li>meta:想將使用者的程式進行設定，或者標記上某些屬性</li>
<li>改變流程: 執行使用者的內容前後，想添加某些程式去執行</li>
</ul>
<h4 id="javaannotation">回頭看看 java annotation</h4>
<p>因此針對第一點，java 提出了 annotation 的概念，但是僅能加上屬性不能改變被標記程式的流程。<br>
所以當初 java 這點被廣泛的應用拿來生成文件以及生成設定檔。<br>
不過在這個流程反轉的年代， java annotation 並沒有因為只能作為 meta 而失去威力。<br>
只要是有套上框架的程式，流程一開始都是交由框架去跑，所以套上框架的程式只要在編譯或是建置的時候，掃描所有 code 裡有 annotation 的地方，便能影響框架使之把控制權交給你，便能演出剛剛 python 裡的 <code>@get('/index')</code> 精彩戲碼</p>
<h4 id="pythondecorator">來看看 python decorator</h4>
<p>在來看看 python 的小老鼠，其實是與 java annotation 有所不同，以往這種想對程式添加東西的動作，在設計模式裡發展出了一個叫做裝飾者模式的東西，使這種添加的動作不會太過難看，所以 python 直接使用 decorator 作為命名啦。</p>
<p>寫一個小小的範例如下</p>
<pre><code>def log(func):
    print(&quot;func name:&quot;, func.__name__)
    return func

@log
def hello():
    print(&quot;hello&quot;)

hello()
</code></pre>
<p>在此可以看到我寫了一個 log 的 function ，這個功能只是把被 log 標記過的 function ，在被呼叫的時候記住一下他的名字。</p>
<p>在這裡的呼叫 hello()時其實它的功能就是轉換成如下面這般形式</p>
<pre><code>log(hello)()
</code></pre>
<p>是請 log 加工一下我的 hello function ，還給我一個加工過的 hello function ，而透過 decorator 可以把這醜陋的加工弄得漂亮一些。<br>
而 code 可以很專注在自己的宣告上面，而 log 就變成了第二級需要注意的資訊，對於開發者大概就知道「喔，大概是要讓這個 function 被紀錄一下吧」，可以很明顯的看到能將眼睛的注意力分為兩種不同的等級。</p>
<h3 id="">小結論</h3>
<p>有些人會覺得這種小小的 meta 功能根本不足以說嘴，但我覺得，多了 annotation 或是 decorator 其實能夠讓程式的閱讀性提升，而且可以少額外寫出一個設定檔的時間，因此我實在不覺得小老鼠是個應該被無視的功能呀 ~</p>
]]></content:encoded></item><item><title><![CDATA[Scheme 中的 quasiquote, unquote, unquote-splicing]]></title><description><![CDATA[<h3 id="schemequote">先談談 Scheme 中的 Quote</h3>
<p>每次我向人介紹 Scheme 的時候，我總是喜歡跟人說 Scheme 語法只有一個：</p>
<pre><code>(函數名稱 參數1 參數2 參數n...)
</code></pre>
<p>在 scheme 如果不是數字或是文字，則會被當成 symbol ，而 symbol 簡言就是被當成某個內容的名稱，像是函數的命名、變數的命名都被稱為 symbol。</p>
<p>只要遇到 symbol ，也就是一個像是變數名稱或是函數名稱的文字，Scheme 都會嘗試去找找看有沒有對應的變數值或是函數。</p>
<p>而今天 Scheme 是可以用同一個語法去表達資料的，所以當你想把同樣語法的東西當成一個 list 或者是你不想讓某個 symbol 被 scheme 當成函數或者變數的時候，此時就能用 ' 放在 symbol 或 list 前面。</p>
<p>如：</p>
<pre><code>'a ;會被當成一個</code></pre>]]></description><link>https://fk.wtf/scheme-zhong-de-quasiquote-unquote-unquote-splicing/</link><guid isPermaLink="false">5b916728a7dce77ebd3443e3</guid><category><![CDATA[scheme]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Fri, 20 Feb 2015 04:43:00 GMT</pubDate><content:encoded><![CDATA[<h3 id="schemequote">先談談 Scheme 中的 Quote</h3>
<p>每次我向人介紹 Scheme 的時候，我總是喜歡跟人說 Scheme 語法只有一個：</p>
<pre><code>(函數名稱 參數1 參數2 參數n...)
</code></pre>
<p>在 scheme 如果不是數字或是文字，則會被當成 symbol ，而 symbol 簡言就是被當成某個內容的名稱，像是函數的命名、變數的命名都被稱為 symbol。</p>
<p>只要遇到 symbol ，也就是一個像是變數名稱或是函數名稱的文字，Scheme 都會嘗試去找找看有沒有對應的變數值或是函數。</p>
<p>而今天 Scheme 是可以用同一個語法去表達資料的，所以當你想把同樣語法的東西當成一個 list 或者是你不想讓某個 symbol 被 scheme 當成函數或者變數的時候，此時就能用 ' 放在 symbol 或 list 前面。</p>
<p>如：</p>
<pre><code>'a ;會被當成一個 atom
'(1 2 3) ;當成一個 list
</code></pre>
<p>如果上述的例子都沒有加上 ' 的話，scheme 就會去看看有沒有 a 這個變數，而 1 也會被誤會成是一個函數，開始進行尋找是不是有跟 a 和 1 能夠配對的變數值以及函數內容</p>
<p>補充一下，其實 ' 符號只是 quote 函數的語法蜜糖而已，實際上它會包裝回 (quote a) 和 (quote (1 2 3)) 是不是看起來就跟原本我說的語法無差異呢?不管是程式或者是資料，都能以函數的方式包裝起來，所以 lisp 才被認為是程式與資料共構的語言。</p>
<p>再稍微補充一點，或許有人會產生一個疑問，<code>'(1 2 3)</code> 與 <code>(list 1 2 3)</code> 到底是差在哪裡? 其實這個狀況換個例子更容易讓人明瞭，如果今天是 <code>'(a b c)</code> 與 <code>(list a b c)</code> 前者基本上就是會保留成 ( a b c ) 的樣子，應為 quote 是表示裡面任何一個元素都不要去動他，保持符號原本的模樣即可。但是後者則會開始被搜尋是否有對應的 a b c 符號的內容，如果發現沒有對應的內容，則會出現錯誤。</p>
<p>以上就是基本 quote 的介紹。</p>
<h3 id="quasiquote">Quasiquote 是什麼?</h3>
<p>基本上 quosiquote 在 scheme 裡面是用 ` 這個符號來表示的，這是在鍵盤上與 ~ 同一個位置的那個符號。這個符號的功能與 quote 幾乎沒有什麼分別。如果單純使用 quote ，則裡頭所有的 symbol 和計算式都不會被計算或是轉換。舉個例子如下:</p>
<pre><code>'(a (+ 1 2))
=&gt; (a (+ 1 2)) ; 原封不動的還給你
</code></pre>
<p>而上面的例子裡，仔細看可能會覺得我想將裏頭的 (+ 1 2) 給計算出來。如果要達到這個目的則需要 ` (quasiquote) 以及 , (unquote) 這兩個特殊的符號來幫忙。</p>
<pre><code>* \` (quasiquote):與 quote 無異，但是期待裡頭會有個 unquote
* , (unquote): 顧名思義，無視 quote 規則，會算出 unquote 後面的數值
</code></pre>
<p>因此上面的例子會變成下面的狀況:</p>
<pre><code>`(a ,(+ 1 2))
=&gt; (a 3) ; unquote 後面的計算式被算出一個數值來了
</code></pre>
<h3 id="unquotesplicing">那什麼是 unquote-splicing 呢?</h3>
<p>在 unquote 遇到計算的結果是個 list 的時候，會原封不動的將 list 放在裡面。如果想要將 unquote 的 list 給拆掉，則需要使用 ,@ (unquote-splicing) 來幫忙。<br>
舉例如下:</p>
<pre><code>`(a ,(list 'b 'c))
=&gt; (a (b c)) ; 明顯與我想要的結果 (a b c) 不同

`(a ,@(list 'b 'c))
=&gt; (a b c)
</code></pre>
<p>以上就是 quasiquote, unquote, unquote-splicing 的介紹。<br>
補充一下，上面的這些符號跟 quote 一樣都只是一個蜜糖，因此 `(a ,(+ 1 2) 是會被轉換回 (quasiquote (a (unquote (+ 1 2))) 如此的形式，依然符合我一開始所說的 scheme 語法‧</p>
]]></content:encoded></item><item><title><![CDATA[一個二進位方法判斷是否為 2 的次方數]]></title><description><![CDATA[<p>今天看了一個問題，是叫你寫個程式判斷一個數字 n 是否為 2 的次方。</p>
<p>起初一個很簡單的概念就是用个迴圈，從 1 開始不斷的乘 2 ，如果這個數字跟叫你丟進來測試的數字 n 相同，那就是 2 的次方了。</p>
<p>大概長是下面這個樣子：</p>
<pre><code>int det_is_power_by_2(unsigned n)
{
    for (unsigned i = 1; i &lt;= MAX_OF_INT; i * 2) {
        if ( i == n )
            return 1;
            
    }
    
    return 0;
}
</code></pre>
<p>上面是個很淺顯易懂的作法，當然如果不想用乘法，也能用 i &lt;&lt;</p>]]></description><link>https://fk.wtf/yi-ge-er-jin-wei-fang-fa-pan-duan-shi-fou-wei-2-de-ci-fang-shu/</link><guid isPermaLink="false">5b9166cca7dce77ebd3443e1</guid><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 14 Oct 2014 09:51:00 GMT</pubDate><content:encoded><![CDATA[<p>今天看了一個問題，是叫你寫個程式判斷一個數字 n 是否為 2 的次方。</p>
<p>起初一個很簡單的概念就是用个迴圈，從 1 開始不斷的乘 2 ，如果這個數字跟叫你丟進來測試的數字 n 相同，那就是 2 的次方了。</p>
<p>大概長是下面這個樣子：</p>
<pre><code>int det_is_power_by_2(unsigned n)
{
    for (unsigned i = 1; i &lt;= MAX_OF_INT; i * 2) {
        if ( i == n )
            return 1;
            
    }
    
    return 0;
}
</code></pre>
<p>上面是個很淺顯易懂的作法，當然如果不想用乘法，也能用 i &lt;&lt; 1 去做乘 2 的動作，在電腦裡二進位的左移剛好就是乘上 2 ，只有在數字乘到極限的時候，才有可能發生錯誤（溢位）。</p>
<p>不過後來我發現二進位的數學真的是一個沒有極限的領域，除了左移代表乘 2 ，右移代表除 2 的這個例子，剛剛判斷是否為 2 的次方數還能寫成如下的方法：</p>
<pre><code>int det_is_power_by_2(unsigned n)
{
    return n &amp;&amp; !(n &amp; n - 1);
}
</code></pre>
<p>除了行數短，其實也隱含著很特殊的二進位數學的概念，我來解釋一下這段程式碼的原理，不過要先說明一下在傳統的程式語言領域通常 <code>0 為 False，非 0 為 True</code> ，所以一旦有語言無法使用這個概念，那這段 code 就起不了作用了。</p>
<p>首先：</p>
<pre><code>n &amp; n - 1
</code></pre>
<p>這裡的概念真的很酷，因為剛好二進位中，只要是 2 的次方，都剛好會是像 <code>100</code> 或者 <code>1000</code> 這種 1 開頭，尾巴都是 0 的狀況，而這種 2 的次方數減 1 之後，則剛好是 <code>011</code> 或者 <code>0111</code> 這種尾巴都剛好是 1 的狀況。</p>
<p>所以拿 8 來作舉例</p>
<pre><code>8 的二進位 0b1000
7 的二進位 0b0111
</code></pre>
<p>一旦這兩個數字作每個 bit 間的 and 運算（也就是 &amp; 運算），就會變成下面這樣：</p>
<pre><code>0b1000
  &amp;&amp;&amp;&amp;
0b0111
-------------
  0000
</code></pre>
<p>也就是說結果一定會是 0 ，在電腦中代表 False</p>
<p>再來看一個普通一點的狀況，舉個數字 6 來看看是否為 2 的次方</p>
<pre><code>6 的二進位 0b110
5 的二進位 0b101

0b110
  &amp;&amp;&amp;
0b101
------------
  100
</code></pre>
<p>所以當中的結果 0b100 換算成十進位是 4 ，也就是非 0 的結果，所以是個代表 True 的結果</p>
<p>所以單純用 n &amp; n - 1 來計算是否為 2 的次方，若剛好是 2 的次方的話會是 False ，不是 2 的次方剛好會是 True，所以只要在這個前面加個 not 來把運算結果給反過來就行了，所以就是 <code>!(n &amp; n - 1)</code></p>
<p>只不過有個狀況會是個要注意的例外，因為數學當中規定 0 不是任何人的次方，但是根據這種方法去運算， 0 跟 -1 依然得到 True，其中的原理是關於 -1 在二進位裡頭是滿滿的 1 ，假設是 8 位元整數那就是 0b11111111 ，所以滿滿的 1 跟滿滿的 0 去計算結果依然會告訴你 0 是 2 的次方數。</p>
<p>不過還好，邏輯中的 <code>&amp;&amp;</code> 有個神奇的特性， <code>x &amp;&amp; True</code> 中，0 &amp;&amp; True 剛好會是 False ，而前面說過任何非 0 數字都會當成 True。因此任何非 0 的 n &amp;&amp; True 等同於 True &amp;&amp; Ture，所以這個方法可以拿來過濾掉 0 這個特殊的狀況。</p>
<p>這樣講可能稍微有點不明白，那我稍微列個表來做為解說</p>
<p>n &amp;&amp; !(n &amp; n - 1)當中分別代表兩種狀況：</p>
<ol>
<li>
<p>是否為零</p>
</li>
<li>
<p>是否為 2 的次方</p>
<pre><code> 如果是 2 的次方：
 非 0 &amp;&amp; True =&gt; True
 0 &amp;&amp; True =&gt; False
 
 如果不是 2 的次方：
 非 0 &amp;&amp; False =&gt; False
 0 &amp;&amp; False =&gt; False
</code></pre>
</li>
</ol>
<p>這個方法非常的妥善運用到 &amp;&amp; 運算只要遇到一邊有 False 的狀況，結果一定就是 False</p>
<p>我真的覺得早期的人真的非常善用二進位數學的各種特性呀，真想好好的學習各種二進位的思考方式。</p>
]]></content:encoded></item><item><title><![CDATA[關於 python 中的 self]]></title><description><![CDATA[<p>在 python 物件方法中，如果存取一個 class 或者 instance 中的變數，<br>
那麼在物件方法宣告參數時，就必須要有一個 self 當作第一個參數。</p>
<p>大約長得像下面這樣：</p>
<pre><code> class Person:
     def __init__(self, name, age):
         self.name = name
         self.age = age
</code></pre>
<p>看到這個例子中的 self 其實與其他語言如： java, c++ 中的 this 是差不多的東西。<br>
兩者都是代表該 instance 自身</p>
<p>其用途就像這個 python 例子中，初始化的物件方法會傳入一個初始變數 name ，打算讓傳入的變數 name 改變物件裡頭的 name 。有沒有發現上面這句很繞口，這是因為 name 變數重名了，</p>]]></description><link>https://fk.wtf/guan-yu-python-zhong-de-self/</link><guid isPermaLink="false">5b91667da7dce77ebd3443de</guid><category><![CDATA[python]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:14:00 GMT</pubDate><content:encoded><![CDATA[<p>在 python 物件方法中，如果存取一個 class 或者 instance 中的變數，<br>
那麼在物件方法宣告參數時，就必須要有一個 self 當作第一個參數。</p>
<p>大約長得像下面這樣：</p>
<pre><code> class Person:
     def __init__(self, name, age):
         self.name = name
         self.age = age
</code></pre>
<p>看到這個例子中的 self 其實與其他語言如： java, c++ 中的 this 是差不多的東西。<br>
兩者都是代表該 instance 自身</p>
<p>其用途就像這個 python 例子中，初始化的物件方法會傳入一個初始變數 name ，打算讓傳入的變數 name 改變物件裡頭的 name 。有沒有發現上面這句很繞口，這是因為 name 變數重名了，因此 self.name 代表該物件自身的 name 讓傳入的參數與物件自身擁有的 name 不至於混淆。</p>
<p>而在 C++ 和 java 中以 this 來代表自身物件，但是 this 並沒有出現任何宣告就能讓編譯器理解現在的 this 是指誰，因此屬於隱含性質的內建物件。不過這對 python 哲學 <code>Explicit is better than implicit.</code> （明確比不明確要好）。因此 python 更希望讓讀程式碼的人知道 self 的存在，因此要求寫程式的人必須明確的寫上這個函數會傳入 self 物件。</p>
<p>除了 python 自身哲學想要求之外，我還想從兩個方向來談談 self 的產生。</p>
<h3 id="c">以 C 的方法模擬物件</h3>
<p>如果要 C 來模擬簡單的物件導向程式的話，那麼大概會以 struct 來包裝物件中的成員變數，然後在寫幾個函數來專門控制這些成員變數，以下寫一個簡單的例子。</p>
<pre><code>typedef struct Person {
    char *name;
    int age;
} Person;

void Person_init(Person self, char *name, int age) 
{
    self.name = name;
    self.age = age;
}
</code></pre>
<p>很好，現在寫了一個幾乎與上面 python 例子相仿的 C 語言例子，我們用 struct 來包裝 Person 的成員變數來代表 class ，而一個比較明顯的差別就是，python 物件的 function 是直接套在 class Person 裡面的，而這裡則是將變數跟函數分別拆開來寫，然後函數的命名以 Person 開頭來讓讀程式的人了解該函數是專門初始化 Person 的。當然啦，在 C 裡面可以透過函數指標的方式把 init 套進 Person 裡面，但是會複雜到模糊了我想說明的焦點。</p>
<p>那很明顯的可以看到，如果我想要產生物件並初始化我的物件，那麼我必須做出類似像下面這樣的動作：</p>
<pre><code>Person john;
Person_init(john, &quot;John&quot;, 18);
</code></pre>
<p>產生一個 john 物件，然後透過 Person_init 來初始化我的 john 物件，而當中第一個參數則是明確指出我要初始化的是 john 這個物件。</p>
<p>因此在 python 的 self 其實也是基於這種基礎之下來設計的。</p>
<h3 id="python">Python 中實際的轉換</h3>
<p>我稍微擴充一下原本的 Person 方便我接下來的解說：</p>
<pre><code> class Person:
     def __init__(self, name, age):
         self.name = name
         self.age = age

    def addAge(self, num=1):
        # 如果沒有傳入要增加的年齡，預設遞增一歲
        self.age += num
</code></pre>
<p>那麼我接下來想產生一個 john 物件然後增加他的年齡應該會寫成以下這樣：</p>
<pre><code>john = Person(&quot;John&quot;, 18)
john.addAge(5)
</code></pre>
<p>而當中的 <code>john.addAge(5)</code> 按照直觀的理解其實就是讓 john 用自己增加歲數的方法增加五歲。而在背後的 python 其實是轉成下面的程式碼：</p>
<pre><code>Person.addAge(john, 5)
</code></pre>
<p>實際上 addAge 是在 Person 物件之下（在 python 當中，其實 class 也是一種物件，這有待未來解說，所以 all is object 不是 ruby 的專利）</p>
<p>因此呼叫 Person.addAge 方法必須明確的告知是要增加哪個物件裡的年齡，所以 python 物件方法中要求你必須明確的宣告出第一個 self （當然，名字不一定要叫 self ，也能亂取一個像是 this 這樣的名稱），來讓物件方法知道。</p>
<p>在 python 裡實際的呼叫物件方法，也跟 C 語言裡面的簡單模擬物件有異曲同工之妙。第一個參數需要被宣告出是要哪個物件，除了是哲學上的要求，也有部份原因是有這樣的內部轉換。</p>
<p>java 跟 c++ 中的 this ，在 class 這種藍圖中使用 this 比較像是未來任何用到 this 的地方，我都知道是哪個 instance ，就是被 new 給新增出來的這個嘛，何須言明。<br>
而 python 跟 c 屬於裝死不知道，你還是得好好的把東西丟進來說清楚。</p>
]]></content:encoded></item><item><title><![CDATA[lambda 與邱奇數]]></title><description><![CDATA[<h2 id="lambda">lambda</h2>
<p>這幾天研究了一下 lambda 之後，發現 lambda 根本不只是匿名的函數這麼簡單而已。在很早之前邱奇就很想用數學表達世界上所有的事情。而當中為為了設計一套方法來判斷什麼樣的東西是可以拿來被計算的，lambda 就被獨立出來發展了。</p>
<p>而 lambda 運算其實包含的元素其實很簡單，只有包含兩個東西，就是變數跟函數而已。<br>
先講一下如何表示一個 lambda 表達式 ( lambda term )，接著舉幾個例子就能很快看懂這套數學系統了。</p>
<p>lambda 表達式的規則(以下用 t 來代表 lambda 表達式，變數用 x 來代表）：</p>
<ol>
<li>x</li>
<li>λx. t</li>
<li>t t</li>
</ol>
<p>光是自己取名一個變數 x, y , z 就能構成基本的 lambda 函數，不過這裡的變數更精確一點的說應該是符號，只要是自己設計的系統中可以拿來用的符號像是 1, 2, 3, x,</p>]]></description><link>https://fk.wtf/lambda-yu-qiu-qi-shu/</link><guid isPermaLink="false">5b916628a7dce77ebd3443d8</guid><category><![CDATA[lambda]]></category><category><![CDATA[python]]></category><category><![CDATA[scheme]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:13:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="lambda">lambda</h2>
<p>這幾天研究了一下 lambda 之後，發現 lambda 根本不只是匿名的函數這麼簡單而已。在很早之前邱奇就很想用數學表達世界上所有的事情。而當中為為了設計一套方法來判斷什麼樣的東西是可以拿來被計算的，lambda 就被獨立出來發展了。</p>
<p>而 lambda 運算其實包含的元素其實很簡單，只有包含兩個東西，就是變數跟函數而已。<br>
先講一下如何表示一個 lambda 表達式 ( lambda term )，接著舉幾個例子就能很快看懂這套數學系統了。</p>
<p>lambda 表達式的規則(以下用 t 來代表 lambda 表達式，變數用 x 來代表）：</p>
<ol>
<li>x</li>
<li>λx. t</li>
<li>t t</li>
</ol>
<p>光是自己取名一個變數 x, y , z 就能構成基本的 lambda 函數，不過這裡的變數更精確一點的說應該是符號，只要是自己設計的系統中可以拿來用的符號像是 1, 2, 3, x, y, z, +, - 都能夠拿來使用</p>
<p>接著如果要表示一個可以傳入參數的函數來達成 x + 1 這個動作，<br>
以往的數學符號裡我們會表達成：</p>
<pre><code>f(x) = x + 1
</code></pre>
<p>在數學裡面我們要自己為這個函數取名叫做 f ，但是在 lambda 只關心傳入的變數還有函數運算的本體而已，所以上面的例子我們可以改成像下面這樣：</p>
<pre><code>λx. x + 1
</code></pre>
<p>我們用 λ 表示接下來是一個可以讓人傳入參數 x 的 lambda 表達式，而參數 x 跟函數的本體則是用 <code>.</code> 去隔開，這樣就構成函數的基本宣告了。</p>
<p>談到現在還有奇怪的地方，那就是講解到現在只有講出怎麼表達一個函數，那我要怎麼樣把數字丟進我的函數去計算呢？<br>
那就是第三條規則啦！</p>
<p>看到 t t 這條規則，其中一個應用就是把右邊的表達式丟到左邊去運算，舉個例子比較好明白：</p>
<pre><code>(函數)      (要丟入的參數)
(λx. x + 1)(5)
=&gt; 6 #這行是說明計算的結果為 6 ，箭號並不是表達式的意思
</code></pre>
<p>這個表達方式代表我把 5 丟到左邊運算式去計算，但是為了避免 5 被當成左邊 lambda 表達式的本體，所以用括號區隔開來說明。</p>
<p>如果現在我們需要傳入兩個參數給 lambda 函數要怎麼辦呢？其實依然可以透過這個規則去表達。<br>
不過在這之前先猜一下要怎麼去宣告這個函數是包含兩個參數呢？我們可能會猜想成下面這種方法：</p>
<pre><code>λx y. x + y #wrong
或者
λx, y. x + y #wrong
</code></pre>
<p>基本上 lambda 函數遵循古老的數學模型，就是<code>函數只有一個參數輸入</code><br>
當然某些支援 lambda 的程式語言是可以直接表示出有多個參數的 lambda 表達式。<br>
但是為了符合數學的概念<br>
所以我們需要把上面的方法改寫一下，透過第三個規則將他寫成 lambda 包住 lambda 的方式：</p>
<pre><code>λx.λy. x + y
等同於
(λx.(λy. x + y))
</code></pre>
<p>這個轉換過程也稱為 currying 。這種表達方式代表我 λx. 後面的函數本體是 λy. x + y ，如果有參數丟進來，我會把函數本體 λy. x + y 所有的 x 給換掉，就剩下 (λy. 傳入的某東西 + y) ，如果再傳入一個參數又會換掉 y 。<br>
所以說如果有數字傳入 lambda 裡面，會把丟進去的參數，從左到右一個一個丟進去，一樣拿 x + y 的例子來解釋：</p>
<pre><code>(函數)            (參數 1)(參數 2)
(λx.(λy. x + y)) (4) (8)
=&gt; (λy. 4 + y)(8) # 把第一個參數 4 丟進去把所有的 x 都換成 4
=&gt; 4 + 8          # 把第二個參數 8 丟進去換掉所有的 y
=&gt; 12
</code></pre>
<p>我也可以把 lambda 做得複雜一點，把函數當成參數丟進去</p>
<pre><code>(函數)       (參數 1)   (參數 2)
(λf.λx. f x)(λa. a + 1)(5)
=&gt; (λx.(λa. a + 1) x) (5) # 將 f 代換為第一個參數 (λa. a + 1)
=&gt; (λa. a + 1)(5)         # 將 x 代入第二個參數 5 
=&gt; 5 + 1                  # 將 a 代入參數 5
=&gt; 6
</code></pre>
<p>這段說明了丟進去的參數，不只有簡單的數字符號，也能再把另一個 lambda 函數丟進去計算。<br>
光是這三個規則的結合方式就能構組成很多東西，也促進了 functional language 的發展，如 Lisp, Scheme, Pyhton, Haskell</p>
<p>看到這裡已經對於表示 lambda 跟計算 lambda 有了基本的認識了，但是仔細套用這三個規則會發現還有一個規則沒有用上<br>
如果今天左邊的函數是個變數 x，例如下面這樣：</p>
<pre><code>(5)((λx. x + 1)
</code></pre>
<p>這樣依然符合規則，不過其意義等到講完邱奇數會比較讓人明白一點。</p>
<h2 id="">邱奇數</h2>
<p>看了 lambda 的使用方式之後，也能了解 lambda 說明了所有的事物都能用函數來表示。而邱奇更是進一步的把像是基本的自然數、加減乘除這類的東西也用 lambda 來表示。</p>
<p>起初小弟我真的看不太懂邱奇表達自然數的方式，所我先從他表示布林函數的方式來介紹好了。<br>
布林函數有 true 跟 false 兩個值，在數位系統中則可能為 0 跟 1。</p>
<p>這就麻煩了呀，邱奇不想被 0, 1 跟 true, false 先給卡住，他希望不管如何，我先用 lambda 函數表示出來就對了，那些符號之類的絕對不是布林函數的重點，我先把他表示出來，到時候你在告訴我你要用什麼符號來表示就好了。</p>
<p>所以邱奇的布林表示方式像是下面這樣：</p>
<pre><code>true = λx.λy. x
false = λx.λy. y
</code></pre>
<p>如果寫成 scheme 跟 python 的話會是這樣：</p>
<pre><code>Scheme:
(define true (lambda (x y) (begin x))) #直接用雙參數的方法表示了

Python:
true = lambda x, y: x
</code></pre>
<p>可以看到 true 跟 false 等待人家輸入兩個參數，分別假設為 x 跟 y ，對於 true 跟 false 只不過是兩個相反的值罷了。所以 true 這邊永遠傳回 x 而 false 傳回 y，這樣一來不管 x, y 輸入些什麼東西，永遠不會相同了。</p>
<p>因此如果要達到數位世界的 true false 那我們可以將 lambda 改成這樣：</p>
<pre><code>true = (λx.λy. x)(1 0) =&gt; 1
false = (λx.λy. y)(1 0) =&gt; 0
</code></pre>
<p>這種函數表達的概念在接下來介紹邱奇的自然數（正整數）時很重要，邱奇依然想把一些東西抽掉，光是靠 lambda 就能夠表達自然數的概念了。</p>
<p>這次邱奇抽走等待使用者去定義的東西有兩個，一個是遞增的方法，另一個是從哪個起始值開始起跳，所以下面把遞增的函數先用 f 來表示，而起始數字用 x 表示：</p>
<pre><code>0 := λf.λx. x
1 := λf.λx. f x
2 := λf.λx. f (f x)
3 := λf.λx. f (f (f x))
下面以此類推
</code></pre>
<p>0 這個數字就是起始值的意思，所以直接保留 x 就好了<br>
1 就是遞增起始值一次的意思，所以透過 f 去遞增 x 一次，那就是 1 的意義了<br>
2 可以看出來是遞增了一遍，又去呼叫 f 再去遞增一遍，所以可以看到 f (f x) 這樣的形式，自然結果就是 2 囉</p>
<p>如果按照地球上的定義，我們遞增的方法其實就是 x + 1 ，而自然數的起始值就是 0。邱奇這種表示方式可能是為了避免某個地方不是遵循這種規則，或許我們有個世界起始值是 0 但是他的遞增方法是 x - 1 的顛倒世界，那邱奇數依然符合他們的自然數。</p>
<p>所以現在我想把邱奇數代入地球的表示方式，我們可以表示成下面這樣：</p>
<pre><code>丟進去的兩個參數都是(λa. a + 1)(0) 第一個參數代表如何遞增，第二個參數代表起始值為 0
下面大中小括號的用途只是作分隔而已

0 = (λf.λx x)(λa. a + 1)(0)
=&gt; (λx x)(0) #函數本體沒有用到 (λa. a + 1) 所以代換 f 時，並沒有任何東西出現
=&gt; 0 

-----------------------------
1 = (λf.λx. f x)(λa. a + 1)(0)
=&gt; [λx.(λa. a + 1) x](0)   #先把第一個參數 (λa. a + 1) 丟進去把 f 換掉
=&gt; [(λa. a + 1)(0)]        #把第二個參數 0 丟進去換掉 x ，結果產生新的函數囉
=&gt; 0 + 1                   #把 0 給丟進去計算
=&gt; 1

-----------------------------
2 = (λf.λx. f (f x)) (λa. a + 1) (0)
=&gt; {λx. (λa. a + 1) [(λa. a + 1) x]} (0)
=&gt; (λa. a + 1) ((λa. a + 1) 0)
=&gt; (λa. a + 1) (0 + 1)
=&gt; (λa. a + 1) (1)
=&gt; 1 + 1
=&gt; 2
</code></pre>
<p>透過上面的計算過程應該可以比較明白如何計算出邱奇自然數了。透過不斷的呼叫遞增函數就能算出我們要的自然數了。<br>
不過這裡有個問題，看到 <code>3 := λf.λx. f (f (f x))</code> 這個樣子，雖然我們可以看懂就是不斷的呼叫遞增函數，但是如果要表達 100 這個自然數，那不是要寫出 100 個 f 去表示要呼叫 100 次遞增函數了嗎？<br>
所以應該還記得上一節講到 <code>(5)((λx. x + 1)</code> 這種奇怪的表達方式吧？這裡就是用來表示，如果未來後面又有個參數丟進來，像是：</p>
<pre><code>[(5)(λx. x + 1)](10)
</code></pre>
<p>這種表示方法意思就類似上面的 f (f (f x))，代表他會套入這個函數 5 次。<br>
所以上面的自然數的部份我們可以稍微改寫一下，變成下面這樣：</p>
<pre><code>λn.λf.λx. n f x # n 代表你需要的是第幾個自然數
</code></pre>
<p>拿剛剛的自然數 3 下去的算的話，大致的運算會是這樣：</p>
<pre><code>(λn.λf.λx. n f x)(3)(λa. a + 1)(0) # 3 表示我要第幾個自然數，最右邊兩個參數依然跟前面相同
省略前面的代換過程
=&gt; (λa. a + 1)(0)
=&gt; (λa. a + 1)(0+1)   # 第一次把參數丟進去 +1
=&gt; (λa. a + 1)(0+1+1) # 第二次把參數丟進去 +1
=&gt; (0+1+1+1)          # 第三次把參數丟進去 +1

這個過程不太正式啦，但是比較好理解
當然也可以直接先寫成
f (f (f x))
=&gt; 長太醜我不寫了
</code></pre>
<p>到這裡才算真的把 lambda 表達的方式完全講完了，但是邱奇設計的這套 lambda 可以做的事情可沒有那麼少。<br>
他也能拿來表示基礎的四則運算，當然他也抽走了基本的元素，讓他能符合不同世界的要求，下面用加法來舉例</p>
<p>加法如下面這個樣子表示：</p>
<pre><code>λm.λn.λf.λx. m f (n f x)
</code></pre>
<p>這個加法的方式可以讓人丟入四個參數，裡面的 f 跟 x 一樣是像前面所講的那樣，一樣是被抽掉的遞增方法 f 跟起始數值 x。所以 m 跟 n 就是用來相加的兩個數字囉。</p>
<p>有沒有看到很熟悉的一個東西 <code>n f x</code> 是不是就是我前面用來表示自然數 n 的方式呢？<br>
所以 n f x 就是先不斷的重複的使用遞增函數 f ，把起始值加到 n 為止。<br>
這時候就會變成 m f n 這個樣子<br>
再去使用 f 遞加 n 加個 m 遍，這就是 m + n 的作法囉。</p>
<p>邱奇的 lambda 包含了這種基礎四則運算，也能夠計算布林的 and, or, not 我想邱奇可能真的很希望用函數表達世界上的一切吧！<br>
當然邱奇的 lambda 演算還有一些沒有提到的東西，像是我一開始提到的判斷函數是否可以被計算、兩函數之間是否相同。<br>
甚至在還沒有電腦的時代，就開始探討如果這些函數的變數有型別的話會如何。因此電腦這塊就開始有一些型別推導之類的東西出現可以讓人研究。</p>
<h3 id="">參考資料：</h3>
<p><a href="https://en.wikipedia.org/wiki/Lambda_calculus">wiki</a></p>
]]></content:encoded></item><item><title><![CDATA[python 的 iterator]]></title><description><![CDATA[<h2 id="foriterator">for 迴圈跟 iterator (可走訪物件、迭代器）</h2>
<p>很多人在初學 python 的時候，都會搞不懂 for 迴圈到底是在做些什麼<br>
初學 python 應該會看到這樣的 for 迴圈</p>
<pre><code>for i in range(10):
    print(i)
</code></pre>
<p>i 從 0 遞增到 9，然後每遞增一次，就執行 print(i) 。</p>
<p>那為什麼我們會搞不清楚 python for 呢？<br>
因為以往的語言，裡面的 for 都指是 while 的精煉版，所以從 while 學到 for 並不會有不適應。<br>
但是這不符合 python 中「</p>]]></description><link>https://fk.wtf/python-de-iterator/</link><guid isPermaLink="false">5b9165e2a7dce77ebd3443d5</guid><category><![CDATA[python]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:12:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="foriterator">for 迴圈跟 iterator (可走訪物件、迭代器）</h2>
<p>很多人在初學 python 的時候，都會搞不懂 for 迴圈到底是在做些什麼<br>
初學 python 應該會看到這樣的 for 迴圈</p>
<pre><code>for i in range(10):
    print(i)
</code></pre>
<p>i 從 0 遞增到 9，然後每遞增一次，就執行 print(i) 。</p>
<p>那為什麼我們會搞不清楚 python for 呢？<br>
因為以往的語言，裡面的 for 都指是 while 的精煉版，所以從 while 學到 for 並不會有不適應。<br>
但是這不符合 python 中「所有的事情，都只用一個方法做到」。</p>
<p>而 python 更認為 for 的用途就是拿來把物件給走一遍<br>
包括像是 [1, 2, 3] 的 list 或是 {1: 'a', 2: 'b'} 的 dict 還有剛剛談到的 0 ~ 9 的數字都適合拿來走訪</p>
<p>whlie 就專心在他的條件判斷，而 for 則是走一圈物件裡面所有的東西<br>
那 for 到底是怎麼做到「走一圈」這件事呢？</p>
<p>簡單來講就是拿到 iterator （可走訪物件），然後走訪</p>
<p>拿 <code>for i in xxx:</code> 來舉例<br>
他做了兩個動作：</p>
<ol>
<li>
<p>抓取 xxx 的可走訪物件，來判斷可否走訪：<br>
實際上是使用 iter(xxx) 去抓，其實動作也很簡單，就是從 <code>xxx.__iter__()</code> 取取看，如果有 <code>__iter__()</code> 這個方法，那就拿 <code>__iter__()</code> 回傳的可走訪物件來用，如果沒有 <code>__iter__()</code> 這個方法， iter(xxx) 就理所當然說 type error，這物件是無法被 for 迴圈走訪的。</p>
</li>
<li>
<p>開始走訪 iter() 回傳的物件，取得可走訪物件的下一個值：<br>
拿到回傳的可走訪物件之後，就會用 next(可走訪物件) ，去一次又一次的跑，然後把回傳的值丟給 i ，所以我們 for 迴圈裡面就能拿到 i 這個值，直到遇到 StopIteration 這個例外被丟出來為止，而 next() 做的事情不過就是抓取 <code>可走訪物件.__next__()</code> 回傳回來的東西而已。</p>
</li>
</ol>
<p>所以我們的物件只要擁有<code>__iter__()</code> 跟 <code>__next__()</code> 這兩個方法，管他裡面有什麼黑箱子，都能夠被 for 拿來使用</p>
<p>以下使用 iter() 跟 next() 來做示範一個 python list 是怎麼讓 for 去走訪的</p>
<pre><code>&gt;&gt;&gt; it = iter([5, 6, 7, 8]) # 先抓他的可走訪物件
&gt;&gt;&gt; next(it) # 取得可走訪物件的下一個值
5
&gt;&gt;&gt; next(it)
6
&gt;&gt;&gt; next(it)
7
&gt;&gt;&gt; next(it)
8
&gt;&gt;&gt; next(it) # 噴出 StopIteration 的例外
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
StopIteration
</code></pre>
<p>接著再往內透視一點點：</p>
<pre><code>&gt;&gt;&gt; it = [5, 6, 7, 8].__iter__()
&gt;&gt;&gt; it.__next__()
5
&gt;&gt;&gt; it.__next__()
6
&gt;&gt;&gt; it.__next__()
7
&gt;&gt;&gt; it.__next__()
8
&gt;&gt;&gt; it.__next__()
Traceback (most recent call last):
  File &quot;&lt;stdin&gt;&quot;, line 1, in &lt;module&gt;
StopIteration
</code></pre>
<p>python 的作者 Guido 很喜歡這種黑箱子型別，又稱為 duck type，因為只要這東西會在水裡游、會呱呱叫、有翅膀，那我就把這東西當作鴨子。<br>
因此我們接下來也做一隻可以被 for 迴圈拿來用的鴨子。</p>
<h2 id="">實作可走訪物件</h2>
<p>我們來做一個類似 range 的事情好了， range(10) 的範圍是從 0 ~ 9 ，那我們現在設計的 myrange 做的事情跟 range 不同。<br>
我希望 myrange 能給我起跳數字為 1 然後遞增到 10 為止 ( 1 ~ 10 )。</p>
<h5 id="">範例</h5>
<pre><code>class myrange:

    def __init__(self, start = 0, end = None, step = 1):
        # 判斷參數是否有提供 end，如果沒有提供 end 則 start 為結束值
        # 從 0 跑到 end
        if end == None:
            self.index = 0
            self.start = 0
            self.end = start

        # 三個參數都有提供的話，從 start 跑到 end 為止，每一次遞增 step
        else:
            self.index = start
            self.start = start
            self.end = end

        self.step = step

    def __iter__(self):
        # 當 iter() 呼叫時，會來這裡要一個可走訪的物件
        # 而我們也有 __next__() 方法可以讓人走訪，所以我們回傳 self 
        # 讓 next() 呼叫 self.__next__()
        # 同時代表著，我們也能不做出 __next__() ，而是回傳其他的可走訪物件
        # 像是回傳 [1, 2, 3].__iter__() 一樣也能被 for 迴圈走訪

        return self

    def __next__(self):
        self.index += self.step

        #記得要丟出 StopIteration 例外讓 for 迴圈停止，而這裡只是判斷超出範圍就丟例外
        if self.start &lt; self.end and not self.start &lt; self.index &lt;= self.end:
            raise StopIteration

        elif self.start &gt; self.end and not self.start &gt; self.index &gt;= self.end:
            raise StopIteration

        return self.index

    for i in myrange(10):
        print(i)
</code></pre>
<p>而我這邊不斷講到的可走訪物件，其實有個比較正式的翻譯叫做<code>迭代器</code>，就是每次都會把一個東西的回傳給你，不斷的代換。</p>
<p>而實作 <code>__iter__()</code> 出來的東西，就能玩完全全被 python 當成可迭代的物件，<br>
而在範例的註解當中我也強調了一點， <code>__next__()</code> 可以不用被實作出來，可以替換成其他任何東西的迭代器<br>
讓 <code>next()</code> 去抓取其他物件的 <code>__next__()</code> 一樣能讓 for 迴圈跑起來，<br>
這就是在 python 之中，duck type 被靈活運用的部份了</p>
]]></content:encoded></item><item><title><![CDATA[Ruby, Python, NodeJS, PHP 小看法]]></title><description><![CDATA[<p>最近在 <a href="http://www.codecademy.com/">Codecademy</a> 把 Ruby 這個我沒學過的語言給跑了一遍，之前我是覺得這語言有點醜啦，但深入了解一下之後，我發現是有他的哲學存在的。<br>
所以我現在想稍微比較一下我碰過的語言，比較一下社群的生態</p>
<h2 id="ruby">Ruby</h2>
<p>先拿 Ruby 來聊聊，因為才正剛好跑完一趟他的教學。一開始我看到 Ruby 的 Block 是用 end 結束，我就聯想到 Pascal 這個號稱當代最美的程式語言。</p>
<p>Pascal 真的很美，也幾乎都做得很好，但是美中不足的就是 begin - end 來當作程式的 block ，換在 C 或是絕大部分語言就是 '{', '}' 這兩個括號<br>
為什麼美中不足，就是因為當一個軟體開發變得很大的時候，過多的巢狀 begin 跟 end 在程式碼裡面，是會讓眼睛花掉的，</p>]]></description><link>https://fk.wtf/ruby-python-nodejs-php-xiao-kan-fa/</link><guid isPermaLink="false">5b91658ca7dce77ebd3443cd</guid><category><![CDATA[php]]></category><category><![CDATA[python]]></category><category><![CDATA[nodejs]]></category><category><![CDATA[ruby]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:12:00 GMT</pubDate><content:encoded><![CDATA[<p>最近在 <a href="http://www.codecademy.com/">Codecademy</a> 把 Ruby 這個我沒學過的語言給跑了一遍，之前我是覺得這語言有點醜啦，但深入了解一下之後，我發現是有他的哲學存在的。<br>
所以我現在想稍微比較一下我碰過的語言，比較一下社群的生態</p>
<h2 id="ruby">Ruby</h2>
<p>先拿 Ruby 來聊聊，因為才正剛好跑完一趟他的教學。一開始我看到 Ruby 的 Block 是用 end 結束，我就聯想到 Pascal 這個號稱當代最美的程式語言。</p>
<p>Pascal 真的很美，也幾乎都做得很好，但是美中不足的就是 begin - end 來當作程式的 block ，換在 C 或是絕大部分語言就是 '{', '}' 這兩個括號<br>
為什麼美中不足，就是因為當一個軟體開發變得很大的時候，過多的巢狀 begin 跟 end 在程式碼裡面，是會讓眼睛花掉的，可讀性大大的降低。</p>
<p>不過我想 Ruby 應該是有考慮到這點，所以絕大部分的語法像是 if, else, method, class 是沒有 begin 只有 end 代表宣告這段 code 的結束。</p>
<p>而我之所以突然不覺得 Ruby 有我想得那麼糟，是因為 Ruby 的功能之強，必須在語言的可讀性和強度間作到一個平衡，他的可讀性絕對沒有 Python 好。 但是已經可以讓人看懂了，而除了一般語法就夠好用之外，也生了算是蜜糖的東西讓開發者用簡單的語法寫出以往是比較長的程式碼。</p>
<p>但是程式碼短，並不代表可讀性高，舉個 push 的例子。</p>
<pre><code>[1, 2, 3].push(4)
[1, 2, 3] &lt;&lt; 4
</code></pre>
<p>這兩個用途是一樣的，但後者是一個蜜糖，讓你可以把東西塞到裡頭，我想 Ruby 哲學應該是「少勝於多」，所以小弟我在練習的時候，有些許的壓力。<br>
因為有很多很棒的東西可以幫你縮短語法，但是又很怕哪一天沒記住，就少了一個強而有力的工具。其實這部份的「強」真的是跟 Perl 有得比。</p>
<p>但我不喜歡 Ruby 的其中一個點就是 Ruby 的語法因為有太多方法作到同一件事情，很沒有一致性，雖然是很方便沒錯，但是比較沒有共同的規範。<br>
舉個例子來講，我覺的 Ruby 呼叫 method 的時候可以不用括號來丟參數是很不錯，以往要像 <code>Hello(&quot;FreedomKnight&quot;)</code> 這樣，現在可以</p>
<pre><code>def Hello name
    puts &quot;Hello #{name}&quot;
end

Hello &quot;FreedomKnight&quot; #不需要括號就能夠呼叫 Hello
</code></pre>
<p>但是那個括號是可選可不選的，雖然這樣看起來像 tcl 這種命令式語言一樣輕鬆，但是我卻不能做到我以為可以做到的單行宣告（參數跟程式碼在同一行會混淆直譯器），<br>
像是 <code>def Hello name puts &quot;Hello #{name}&quot; end</code> ，我是有找到可以作到單行宣告的方法，但是就像是前面的蜜糖那樣，又多了很多方法作到同一件事。題外話，其實我最初以為加個 do 在中間讓他看起來像個 Block 就可以，但好像行不通。</p>
<p>基本上，我覺得 ruby 的哲學是在可讀性跟功能性取平衡。因此功能很多，而且不少是直接降到語法、語言層次，而不是以 API 或是 function 的方式處理，在不熟 ruby 的階段，會有害怕某些強大功能沒記起來的壓力。</p>
<h2 id="python">Python</h2>
<p>Python 的哲學我想大家都知道，就是簡潔、同一件事盡量只有一種方法做到。跟 ruby, perl 的哲學完全相反，以往是因為 Python 才對 ruby, perl 有起了小反感，直到我這陣子摸了 ruby ，只能說哲學不同而已。</p>
<p>Python 一切就很好，也很會斟酌新功能的可讀性與美感，就像 Guido 所想的那樣，他認為一個 programmer 讀 code 比寫 code 的時間還要多，因此才要加強一個語言的可讀性，也生出了 <a href="http://www.python.org/dev/peps/pep-0008/">PEP 8</a> 這樣的規範。</p>
<p>換句話說，Python 跟我一樣有偏執狂，甚至從 Python 2 升級到 Python 3 時，把以往設計不好的地方給大改，完全不相容。是讓語言變好了，但對軟體界是個大傷害，Python 3 出到現在也好幾年了，卻還有一些軟體卡在 Python 2 升不上來，而 PyPI 裡的 Package 還要特地標註為 Python 3。</p>
<p>而偷看了一下 ruby 跟 nodejs 的崛起，其實有很大部份是靠他們的官方 package repo ，像是 gem 跟 npm ，而 Python 卡在這個版本的鴻溝之外，也沒有一個官方的 repo 系統（python 3.4 終於準備要包進 pip 了），只有兩個第三方的軟體 pip 跟 easy_instell，剛玩 python 應該都還不知道有這麼方便的 repo ，Python 應該考慮把 PyPI 經營成 gem 那個樣子。</p>
<h2 id="nodejs">NodeJS</h2>
<p>這東西我玩不多，但是我知道很多人對 js 有著厭惡感，其實我相信，這絕對是拿以往學程式的經驗跳過來。發現 js 的物件機制怎麼跟以往不同。還有為什麼 js 這麼多匿名的 function 。如果對 js 有厭惡感應該得細心的體會一下這些呀！匿名的 function 非常的 event driven 的呀！</p>
<p>不少先入為主的觀念卡在 js 上，但是時間讓 js 從瀏覽器上當作跑馬燈的工具 -&gt; 瀏覽器上的王者前端語言 -&gt; 我何必後端要用其他語言呢？跟前端一樣就好了</p>
<p>而 NodeJS 雖然很年輕，但是成長幅度卻是眾多語言當中，爬升最快的語言，當然 npm 也是對社群幫助很大。</p>
<h2 id="php">PHP</h2>
<p>跟 js 比起來，PHP 的誤會也不少，因為 PHP 早期可是為了讓初學網頁的人，都能用直觀的方式寫後端，所以他設計成嵌入在 HTML 當中。也就是可以當作樣板引擎，當看到 PHP 的標籤，就把標籤內的東西全部轉換成 HTML。</p>
<p>而早期為了簡單，對物件導向的支援根本趨近於零。但是近期已經強化超級多，我覺得到 5.5 已經差不多完整一切了。但是許多人還是拿舊印象來打 PHP。</p>
<p>PHP 看到 npm 跟 gem 之後，社群也開始在思考 pear 的缺點，而開出一個新的計畫叫做 composer ，讓人人都有機會可以把 package 丟上去，而且拿來管理專案的dependency 也超棒，我比較相信 PHP 未來只會越來越壯大，而不會被罵到變小。</p>
]]></content:encoded></item><item><title><![CDATA[PHP 對空字串的 json_encode 跟 json_decode]]></title><description><![CDATA[<p>這兩天好好的研究一下 php 的 source code ，接著打算試著回饋補釘給 php 上游 因此我到 php bug reporting 找了一個看起來蠻簡單的 bug 來修 <a href="https://bugs.php.net/bug.php?id=65780">傳送門</a></p>
<p>把重點整理出來一下</p>
<pre><code>Test script:
---------------
var_dump( json_decode( json_encode( &quot;&quot; ) ) );


Expected result:
----------------
null

Actual result:
--------------
string '' (length=0)
</code></pre>
<p>看起來像是簡單的 bug ，我想說真的賺到了一個簡單的 bug 可以練習，只是不知道為什麼這種簡單的 bug 都沒人來修呢？<br>
怎麼可能放了這麼久都沒人遇到。</p>
<p>這個 bug</p>]]></description><link>https://fk.wtf/php-dui-kong-zi-chuan-de-json_encode-gen-json_decode/</link><guid isPermaLink="false">5b916532a7dce77ebd3443c8</guid><category><![CDATA[php]]></category><category><![CDATA[json]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:10:00 GMT</pubDate><content:encoded><![CDATA[<p>這兩天好好的研究一下 php 的 source code ，接著打算試著回饋補釘給 php 上游 因此我到 php bug reporting 找了一個看起來蠻簡單的 bug 來修 <a href="https://bugs.php.net/bug.php?id=65780">傳送門</a></p>
<p>把重點整理出來一下</p>
<pre><code>Test script:
---------------
var_dump( json_decode( json_encode( &quot;&quot; ) ) );


Expected result:
----------------
null

Actual result:
--------------
string '' (length=0)
</code></pre>
<p>看起來像是簡單的 bug ，我想說真的賺到了一個簡單的 bug 可以練習，只是不知道為什麼這種簡單的 bug 都沒人來修呢？<br>
怎麼可能放了這麼久都沒人遇到。</p>
<p>這個 bug 我想是因為遇到了下面這種狀況</p>
<pre><code>var_dump(json_decode(&quot;&quot;)); # 回傳 null
</code></pre>
<p>所以直覺上認為他寫的測試程式碼也應該得到 null 。</p>
<p>這裡其實很正常，json_decode 是把 php 的字串轉成 json 物件，所以 <code>json_decode(&quot;&quot;)</code> 時，因為字串裡面什麼東西都沒有，所以 php 會轉成 <code>null</code> （因為最外面那層引號是給 php 看的，實際上要變成 json 字串根本沒東西存在）</p>
<hr>
<p>接著就是原 PO 對 encode 跟 decode 所產生的誤會了。</p>
<p><code>json_encode(&quot;&quot;)</code> 是要把 php 物件轉變成 json 的字串，所以既然現在 encode 的東西是空字串，那麼為了讓 json 讀懂，<br>
所以 php 會產生一個字串裡頭包含要給 json 看的 <code>&quot;&quot;</code></p>
<p>這時候如果把這個變數 dump 出來會看到 <code>string(2) &quot;&quot;&quot;&quot;</code> ，這個意思就是<code>我是個 php 字串，裡面包含 &quot;&quot; 這兩個字元</code> 所以如果再去 decode 一遍的話，當然很自然的會還原成 php 的空字串，<br>
而且同一個東西 php -&gt; json, json -&gt; php 還原回來成一樣的東西是個正確的行為。</p>
<p>所以我想這個原 PO 似乎又沒看清楚誰是誰的括號了，我<a href="http://blog-freedomknight.rhcloud.com/php-string/">這篇</a>有探討了一下引號的特性，有興趣可以看一下。</p>
<hr>
<p>附帶一提，虧我已經把針對特殊狀況的 patch 寫好，要送出我人生第一個送回上游的 patch 了，結果是個烏龍 bug。</p>
]]></content:encoded></item><item><title><![CDATA[初探虛擬機和虛擬化]]></title><description><![CDATA[<p>這幾天小弟我開始接觸虛擬機了，但是許多產品讓人搞得有點頭昏腦脹<br>
因此小弟開始爬文好好的釐清這些有關虛擬化的事情。</p>
<p>小弟目前看到大約有 Xen, KVM, VMware, Virtual Box, Hyper-V 這些產品，因此接下來的介紹會將這些產品慢慢的分類</p>
<p>原來虛擬化中有個東西叫做 Hypervisor 這個實在不知道怎麼翻譯的東西，這東西其實就像是 VM 的控制台，虛擬的作業系統裝在 hypervisor 上面，由 hypervisor 去控制硬體。而當中又依照 hypervisor 的安裝位置分成兩類。</p>
<ul>
<li>
<p>type I : 又稱為 bare-metal hypervisor ，看這個詞大致上就是跟裸機裝虛擬機有點關係，直接裝一層 hypervisor 在空機上面，然後 VM 的系統在安裝在 hypervisor ，這樣的虛擬系統離硬體控制比較接近，VM 要控制的硬體資源直接透過 hypervisor 去操作。</p>
</li>
<li>
<p>type II : 又稱為 hosted hypervisor</p></li></ul>]]></description><link>https://fk.wtf/chu-tan-xu-ni-ji-he-xu-ni-hua/</link><guid isPermaLink="false">5b9164b7a7dce77ebd3443c4</guid><category><![CDATA[vm]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:09:00 GMT</pubDate><content:encoded><![CDATA[<p>這幾天小弟我開始接觸虛擬機了，但是許多產品讓人搞得有點頭昏腦脹<br>
因此小弟開始爬文好好的釐清這些有關虛擬化的事情。</p>
<p>小弟目前看到大約有 Xen, KVM, VMware, Virtual Box, Hyper-V 這些產品，因此接下來的介紹會將這些產品慢慢的分類</p>
<p>原來虛擬化中有個東西叫做 Hypervisor 這個實在不知道怎麼翻譯的東西，這東西其實就像是 VM 的控制台，虛擬的作業系統裝在 hypervisor 上面，由 hypervisor 去控制硬體。而當中又依照 hypervisor 的安裝位置分成兩類。</p>
<ul>
<li>
<p>type I : 又稱為 bare-metal hypervisor ，看這個詞大致上就是跟裸機裝虛擬機有點關係，直接裝一層 hypervisor 在空機上面，然後 VM 的系統在安裝在 hypervisor ，這樣的虛擬系統離硬體控制比較接近，VM 要控制的硬體資源直接透過 hypervisor 去操作。</p>
</li>
<li>
<p>type II : 又稱為 hosted hypervisor ，跟 type I 相反，就是我必須裝作業系統之後，再去安裝 hypervisor ，通常都附在虛擬機軟體了，這種 hypervisor 的控制硬體方式是透過原本的作業系統代為處理。</p>
</li>
</ul>
<p>目前屬於 type I 的有 xen, kvm, VMware ESX/ESXi (後者為免費版本), Hyper-V<br>
而屬於 type II 的則是有 Oracle Virtual Box, Microsoft Virtual PC, VMware Workstation/Fusion/Player</p>
<p>而一般使用者好比我，其實只有草草用過 Virtual Box 跟 VMware Player 來快速安裝第二個作業系統，而這種 type II 在國外的教學文章中會用兩個名詞來代表主機的作業系統和虛擬機內的作業系統</p>
<ul>
<li>Host OS: 看 Host 這個字就知道是有人要寄宿在他身上，所以就是指你原本主機上裝的那個系統囉</li>
<li>Guest OS: 跟 Host 相反，就是指虛擬機中的那個作業系統囉。因此在 Virtual Box 有提供一個 Guest Addition 就是給你虛擬機裝的外掛，讓你虛擬機中可以模擬出一些驅動程式這樣。</li>
</ul>
<hr>
<p>再來細講一點 type I 的虛擬化，因為在 Linux 下使用 KVM 還是有點讓人霧煞煞，既然前面說 type I 是直接在裸機上裝一層 VM ，但是為啥麼 KVM 跟 Xen 都會先讓人裝個 OS 再去下載他們執行咧？</p>
<p>原來 type I 中又再分兩種 （怎麼每件事情都分兩種咧？)</p>
<ul>
<li>monolithic hypervisor</li>
<li>microkernel hypervisor</li>
</ul>
<p>其實這兩個字是從作業系統的分類法而來，其中 monolithic 指的就是包山包海，所有的驅動跟要用到的資源一開始就載入作業系統裡，而 microkernel 則是只載入核心的系統，其他資源等需要的時候在載入就好了</p>
<p>而這裡虛擬化的 monolithic hypervisor 則是指這套虛擬機的軟體已經包山包海把驅動這類的東西都已經塞進去了，其實換句話，也就是他們幾乎等於寫了自己的開機核心，而 VMware ESX/ESXi 就屬於這一類。</p>
<p>microkernel hypervisor 的虛擬化，就是因為他們專心寫虛擬化的部份，而載入驅動跟開機的部份則是靠作業系統核心提供，例如 KVM 和 Xen 是靠 Linux ，而 Hyper-V 是靠 windows 的系統核心</p>
<p>(附帶一提， windows 跟 Linux 並不是 Micro Kernel 類型的作業系統，而是他們虛擬化的方式跟作業系統的 Micro Kernel 類似才會被這樣分類取名)</p>
<p>因此 Hyper-V 在宣傳的時候將自己的核心宣傳的非常小，但實際上是透過 windows kernel 去載入其他的資源。</p>
<hr>
<p>還有個名詞叫 半虛擬化/全虛擬化 這兩者的關係其實也並不是透過上面幾點去區分的</p>
<p>而我拿 Linux 來講好了，半虛擬化比較偏向透過 Linux 的核心去 run VM ，因此裝的其他 Linux 如果是同一個 Linux 核心跑起來就很棒，跑起來會蠻快的，畢竟原本就是 Linux 在下面了</p>
<p>但是如果要從頭到腳都要虛擬化一個硬體出來，像是要同時裝 Linux 及 windows 根本無法透過 Linux 核心去跑，所以就要透過全虛擬化了。</p>
<p>這次的初探大致上就到這裡了。</p>
]]></content:encoded></item><item><title><![CDATA[從 Python 樂透小程式看美感]]></title><description><![CDATA[<p>因為最近有需要個類似樂透電腦選號的功能，需要取六個亂數就是了。<br>
當我完成這個小的程式之後，我深深的覺得 python 是個非常具有美感的語言</p>
<pre><code>choiced = [] # 選到的號碼
for i in range(6):
    choiced.append(random.choice([x for x in range(1, 50) if x not in choiced]))
</code></pre>
<p>這已經是我拆出來最重要的三行程式碼了，不過當中最重要的是以下這一段</p>
<pre><code>choiced.append(random.choice([x for x in range(1, 50) if x not in choiced]))
</code></pre>
<p>這行看起來比較長，我將他拆成幾個部份來看</p>
<pre><code>[x</code></pre>]]></description><link>https://fk.wtf/cong-python-le-tou-xiao-cheng-shi-kan-mei-gan/</link><guid isPermaLink="false">5b916469a7dce77ebd3443c1</guid><category><![CDATA[python]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:09:00 GMT</pubDate><content:encoded><![CDATA[<p>因為最近有需要個類似樂透電腦選號的功能，需要取六個亂數就是了。<br>
當我完成這個小的程式之後，我深深的覺得 python 是個非常具有美感的語言</p>
<pre><code>choiced = [] # 選到的號碼
for i in range(6):
    choiced.append(random.choice([x for x in range(1, 50) if x not in choiced]))
</code></pre>
<p>這已經是我拆出來最重要的三行程式碼了，不過當中最重要的是以下這一段</p>
<pre><code>choiced.append(random.choice([x for x in range(1, 50) if x not in choiced]))
</code></pre>
<p>這行看起來比較長，我將他拆成幾個部份來看</p>
<pre><code>[x for x in range(1, 50) if x not in choiced]
</code></pre>
<p>這個用到的是 python 美麗的部份，一個叫做 List Comprehensions 的東西。<br>
這東西就是要產生一個 List ，然後我將這個範圍設定在 1 ~ 49 。抽出來之後不放回去。</p>
<p>其實會有 List Comprehensions 這個東西主要是因為以往我們在數學當中，有個表示集合的訴求。</p>
<pre><code>S = { x | 0 &lt; x &lt; 10, x ∈ N }

可以把上面的數學式換成下面這樣

S = { 1, 2, 3, 4, 5, 6, 7, 8 , 9 }
</code></pre>
<p>簡單來說，我們數學當中已經設計過有關於集合的表示方法，上面是一個表示集合 S 的方式。<br>
這裡所表達的 S 是一個 1 ~ 10 的所有正整數。</p>
<p>而第一種數學的描述方法是說，我的集合 S ，是所有符合條件的 x ，第一點 x 介在 1 ~ 10 ，第二點則是 x 屬於正整數。<br>
那第二種表示方式就是把所有符合結果的 x 跑一遍所得到的結果，當然也比較直觀。</p>
<p>而 python 當中的 List 當然是很適合拿來塞一堆有值的東西，換個概念也能把他當作數學中的集合。<br>
如果搭配著 python 運算中的 and, or, in, not 那不是天下無敵了嗎？<br>
List Comprehensions 就是為了這件事情慢慢衍生而來，如果我們要上面的那個 1 ~ 10 的正整數<br>
可以像下面這樣：</p>
<pre><code>S = [x for x in range(1, 10)]
</code></pre>
<p>而 python 就會把這串中括號包起來的東西轉換成一個包含 1 到 10 的 List 給 S<br>
如果換成別的語言絕對需要很長一段程式碼<br>
或者是一個 function 包起來的 API 組合。</p>
<p>List Comprehensions 還可以搭配著判斷式取 List 中的集合。<br>
假設我們想要：</p>
<pre><code>S = {x | x is even, 1 &lt; x &lt; 50 } // 1 ~ 50 之間的偶數
</code></pre>
<p>對 Python 的 List Comprehensions 來說，只要在 for 的後面加上個條件判斷這樣就可以了</p>
<pre><code>S = [x for x in range(1, 50) if x % 2 == 0]
</code></pre>
<p>如果很直觀的看這一段的程式碼，也能直接解讀成 S 是在 x 介於 1 到 50 之間，而且除以 2 餘數為 0 的所有數字。 這就是一個有美感的程式語言呀！</p>
<p>接著這程式碼剩下的部份我就輕快的帶過， <code>random.choice(List)</code> 就是從 List 中隨機挑選一個值出來。<br>
挑完之後塞到已選數列，下次繼續挑的時候就會被排除了。</p>
<p>接著一個有美感的 Python 例子是當中的三元運算，簡單來說就是一個 if-else 的簡化版。<br>
這東西寫 C 的人很常看見，以下舉例。</p>
<pre><code>int cond = 5;
a = cond &gt; 2 ? 100 : 0;

----- if-else 版 --------

int cond = 5;
if (cond &gt; 2)
    a = 100;
else
    a = 0;
</code></pre>
<p>這東西尤其在寫 Verilog 的時候非常常用，這常常應用在訊號判斷，某 cond 發生時，自動把數值切成 100 不然就是 0。</p>
<p>起初，不少人對三元運算很有意見，當然也包括 Python 的開發者。因為 ? 以及 : 是一個比 if-else 難看懂的符號，<br>
你必須經過學習才能知道符號當中的意思。<br>
再者，Python 的哲學是同樣的事情只用一個方法達成。這對 Python 來說只不過是個 if-else 簡化版而已。</p>
<p>但是三元運算有其方便之處，尤其是你的程式碼已經很長的時候，只為了一個變數的值就加上個 if-else 實在是又臭又長。 舉個例子，如果我想把一個數字的絕對值找出來，我就會用上三元運算</p>
<pre><code>int x = -100;
a = x &gt; 0 ? x : -x;
</code></pre>
<p>如果用上 if-else 大約會多個三行</p>
<pre><code>int x = -100;
if (x &gt; 0)
    a = x;
else
    a = -x;
</code></pre>
<p>這個取絕對值的例子雖然簡潔，但沒學過這個程式語言的人絕對看不懂那個問號，Python 社群中當然也曾經為了這件事情吵過。<br>
最後社群不斷的 argue 語法，終於有個比較好的方案，讓 Python 的作者滿意。</p>
<pre><code>x = -100
a = x if x &gt; 0 else -x # Python 的三元運算
</code></pre>
<p>這就是一個非常 care 美感的語言才會發生的事情，小弟曾在某個 fb 社團跟人家論戰過 C++ 語法美感的問題。<br>
但每一個我不喜歡的語法都被說沒問題，以及有其必要性。</p>
<p>我個人是覺得一定有辦法讓美感提昇，只是當初 C++ 受限於相容 C ，導致美感受限。<br>
跟我論戰的人我想可能是因為寫太久的 C++ 深覺無法變更，以至於都會拿效能問題出來說語法一定得這樣設計，不然就會變慢。</p>
<p>小舉個例子</p>
<pre><code>class A {
public:
    int a;
    int b;
    A() a = 0, b = 0 {
    }
};
</code></pre>
<p>我什麼我很 care 這個呢？因為這個例子同樣也能寫成</p>
<pre><code>class A {
public:
    int a;
    int b;
    A() {
        a = 0;
        b = 0;
    }
};
</code></pre>
<p>會有這兩種語法，當然有其不同點，前者是以一開始就把值塞 0 到 a 跟 b 裡頭，但是後者是以 assign 的方式，建構完之後再把數值 assign 過去。<br>
當初網友就直接告訴我這個就是有效能問題，兩者是不一樣的。</p>
<p>網友講的是沒錯，但多了這個選項讓 C++ 的美感下降，這東西可以交還給編譯器來優化，讓開發者專心於開發上面。</p>
<p>我想當初會選用 C++ 的開發者是因為他是 native 機器碼速度快，同時又有語法支援物件導向。<br>
但既然已經物件導向了，效能勢必下降。而物件導向的優點是有更好的結構，因此伴隨著美麗的語法也很重要。<br>
因此才會有 java 跳出來大改造，把 C++ 會讓人困惑的部份給刪除掉，讓程式感的美感提昇。<br>
雖然 java 最後還為了跨平台這件事情，捨去了一點效能，但 java 的初衷立意良好。</p>
<p>語言只是工具，我們可以多多揣摩當中的美感，但千萬別被工具給限制住了，讓我們看不見當中的美。</p>
]]></content:encoded></item><item><title><![CDATA[Git 的衝突與分支]]></title><description><![CDATA[<h3 id="">關於衝突</h3>
<p>當我們在使用 git 跟人家一起合作時，照著上一次講到的每次都是 pull, commit, push 這三個步驟。<br>
只有一個人的時候還感覺不出有些什麼問題。<br>
但是如果有一個狀況是，我跟其他人 pull 到的瞬間都是相同的程式碼，各自修改了不同的部份之後 commit 接著準備要 push，但好死不死對方比我早 push 回代管主機。<br>
那換成比較慢的我要 push 回代管主機時會發現出現了問題。<br>
主要原因是因為剛剛另一個人已經把代管主機的原始程式碼更新了，所以你原先 pull 到的內容已經過舊囉！</p>
<p>這其實也是為什麼在每次修改程式碼之前都會希望你做一次 pull 的主要原因之一，就是希望自己電腦裡的程式碼是跟代管主機上的版本一樣的新。<br>
那麼這次由於對方已經快了我們一步導致我們 pull 的版本過舊，那我們要怎麼呢？<br>
這種狀況一發生，他上面就會跟你說「版本過舊，請重新 pull」，那他怎麼說就怎麼做就可以了。</p>
<pre><code>git pull
</code></pre>
<p>這時運氣好一點就沒有其他是要做了，因為你跟另一位開發者修改的部份是不同的部份，所以 Git 會很有智慧的幫你解決掉衝突，他會幫你合併代管主機上新版的程式碼到自己的電腦上。</p>]]></description><link>https://fk.wtf/git-de-chong-tu-yu-fen-zhi/</link><guid isPermaLink="false">5b9163f0a7dce77ebd3443be</guid><category><![CDATA[git]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:05:00 GMT</pubDate><content:encoded><![CDATA[<h3 id="">關於衝突</h3>
<p>當我們在使用 git 跟人家一起合作時，照著上一次講到的每次都是 pull, commit, push 這三個步驟。<br>
只有一個人的時候還感覺不出有些什麼問題。<br>
但是如果有一個狀況是，我跟其他人 pull 到的瞬間都是相同的程式碼，各自修改了不同的部份之後 commit 接著準備要 push，但好死不死對方比我早 push 回代管主機。<br>
那換成比較慢的我要 push 回代管主機時會發現出現了問題。<br>
主要原因是因為剛剛另一個人已經把代管主機的原始程式碼更新了，所以你原先 pull 到的內容已經過舊囉！</p>
<p>這其實也是為什麼在每次修改程式碼之前都會希望你做一次 pull 的主要原因之一，就是希望自己電腦裡的程式碼是跟代管主機上的版本一樣的新。<br>
那麼這次由於對方已經快了我們一步導致我們 pull 的版本過舊，那我們要怎麼呢？<br>
這種狀況一發生，他上面就會跟你說「版本過舊，請重新 pull」，那他怎麼說就怎麼做就可以了。</p>
<pre><code>git pull
</code></pre>
<p>這時運氣好一點就沒有其他是要做了，因為你跟另一位開發者修改的部份是不同的部份，所以 Git 會很有智慧的幫你解決掉衝突，他會幫你合併代管主機上新版的程式碼到自己的電腦上。</p>
<p>接著再把這一版的程式碼 commit 後 push 回代管主機就行了。</p>
<p>但是如果好死不死看到了有關 conflict 的訊息，就代表跟另一位開發者同時修改到一樣的程式碼了。<br>
看到 conflict 也不用太驚慌，去剛剛自己修改過程式碼的地方， Git 會提醒你跟另一個開發者衝突到的地方。<br>
不過他是會直接顯示在各個有衝突的檔案裡，所以翻一翻剛剛修改過的檔案，應該會有像下面這樣的文字內容。</p>
<pre><code> &lt;&lt;&lt;&lt;&lt;&lt;&lt; HEAD:mergetest
 我打的內容
 =======
 別人打的內容
 &gt;&gt;&gt;&gt;&gt;&gt;&gt; 4e2b407f501b68f8588aa645acafffa0224b9b78:mergetest
</code></pre>
<p>這個目的就是要檢查哪一個才是要保留的內容，會由 <code>=======</code> 將你寫的內容跟別人改的內人分隔開來。<br>
接著刪掉不要的內容，同時也包括 <code>&lt;&lt;&lt;&lt;&lt;&lt;&lt;</code>, <code>=======</code>, <code>&gt;&gt;&gt;&gt;&gt;&gt;&gt;</code> 這些分隔符號，他們只是代表著衝突的開始、分隔跟結束。<br>
所有衝突都修改之後就能開開心心的 commit 跟 push 囉！</p>
<h3 id="">關於分支與合併</h3>
<p>如果我們在進行開發的時候，程式已經夠穩定， bug 已經少許多了。那我們又想開發新功能，又知道開發新功能一定又會將更多的 bug 帶到程式碼當中。<br>
有沒有更好的解決方案呢？</p>
<p>還有一種狀況就是，當我的軟體已經發佈了第 1.0 版之後，為了滿足繼續維護 1.0 版，減少 1.0 版的重大 bug ，但又要同時開發有許多新功能的 2.0 版。這兩個需求，版本控制系統很早就聽到了，而 Git 當然也能解決這些問題。</p>
<p>在 Git 中，可以使用 branch 去作到分支的效果。簡單來講就是內容同時存在著很多不同的版本。<br>
如果是要解決我上面提到的每個發佈的版本都還要繼續維護，但又不拖累未來的開發，就能在每個發佈的版本繼續開個支線去維護。</p>
<p>稍微做一下示意圖：</p>
<pre><code>       0.1.1   0.2.1
        /       /
     0.1.0   0.2.0
------/------/----------[開發版]--&gt;主線開發
</code></pre>
<p>又或是想要以不影響主線程式的穩定為前提，而繼續開發新功能，也能做個分支出來。等到開發完新的功能之後再合併回主線。</p>
<h4 id="branch">branch</h4>
<p>我們可以很輕易的使用 branch 去打開一個支線</p>
<pre><code>git branch [支線名稱]
</code></pre>
<p>如果沒有打上支線名稱的話， Git 會顯示目前所有的支線。如果打上支線名稱的話， Git 就自然而然會幫你生出一個支線。</p>
<h4 id="checkout">checkout</h4>
<p>接著，產生完支線之後，就是要有辦法可以在各個主線、支線中切換，我們可以使用 checkout 這個指令來幫忙。</p>
<pre><code>git checkout 支線名稱/檔案名
</code></pre>
<p>當 checkout 一個支線名稱的時候，在 Git 中的確是切換到不同的支線。但你會發現，你打開的檔案根本沒有隨著支線的切換，而有不同的內容。<br>
主要是因為每次都將所有檔案內容都改成該支線的內容對電腦來說是很沒效率的。所以可以透過 <code>checkout 檔案名稱</code> 來把這份檔案的內容改成該支線應該要有的內容。</p>
<p>附帶一提，有些地方會說 checkout 可以作到還原的動作。這是因為在你 commit 之後做了修改，但又沒有 commit 這些修改的話， checkout 照剛剛說的是會把這份檔案改成該支線應該有的內容，所以說這份檔案中所有尚未 commit 的內容當然都會消失囉！</p>
<h4 id="merge">merge</h4>
<p>最後當然就是將開發新功能的分支合併回主線當中囉！不過這並不是必要的，因為就我剛剛所說的，對每個發佈的版本持續做維護，其實沒必要將這些額外的分支合併回主線，那如果我真的想把支線合併回來該怎麼做呢？</p>
<pre><code>git merge 支線名稱
</code></pre>
<p>這個指令就能將整個支線合併回主線囉！不過要特別注意的就是，合併依然會有 conflict 的問題，而解決方法就如同我前面講的那樣，照著前述的方法解決就行了。</p>
]]></content:encoded></item><item><title><![CDATA[PHP 的 Cookie 與 Session]]></title><description><![CDATA[<p>這次想談到的主題跟 php 的 session 有關，這東西的產生當然也是一步一步的演進。<br>
網頁在網路上，一開始其實單純只是想要有一個分享文章的空間。 並沒有想到會有今天如此強大的應用。</p>
<p>當初在設計網頁瀏覽時，主要分為兩個部份</p>
<ol>
<li>協議</li>
<li>內容</li>
</ol>
<h5 id="">協議</h5>
<p>這部份主要是是軟體在處理的，我們必須知道，上網的時候是靠軟體抓取網頁的內容的，那軟體要如何知道要抓哪一個網頁呢？</p>
<p>又或者我要如何告訴網頁，我現在要把我的帳號密碼輸入給伺服器呢？</p>
<p>因此，所謂的協議，其實就如同公文一般的存在。必須寫出特定的內容，讓兩邊的軟體知道你想要做什麼<br>
例如：</p>
<pre><code>    i want /index.html  
    字面上可能代表我要 index.html 這份檔案
</code></pre>
<p>我的伺服器程式只要做出分析字串的功能，當我看到 &quot;i want&quot; 就開始準備知道要把檔案抓出來準備送出。</p>
<p>接著又讀到一串文字 &quot;/index.html&quot; 就知道這個檔案是在哪個位置，然後送出去</p>
<p>但是又不能每個軟體都用自己的一套做法，不然我今天想做瀏覽器軟體，</p>]]></description><link>https://fk.wtf/php-de-cookie-yu-session/</link><guid isPermaLink="false">5b916374a7dce77ebd3443b7</guid><category><![CDATA[php]]></category><category><![CDATA[cookie]]></category><category><![CDATA[session]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:04:00 GMT</pubDate><content:encoded><![CDATA[<p>這次想談到的主題跟 php 的 session 有關，這東西的產生當然也是一步一步的演進。<br>
網頁在網路上，一開始其實單純只是想要有一個分享文章的空間。 並沒有想到會有今天如此強大的應用。</p>
<p>當初在設計網頁瀏覽時，主要分為兩個部份</p>
<ol>
<li>協議</li>
<li>內容</li>
</ol>
<h5 id="">協議</h5>
<p>這部份主要是是軟體在處理的，我們必須知道，上網的時候是靠軟體抓取網頁的內容的，那軟體要如何知道要抓哪一個網頁呢？</p>
<p>又或者我要如何告訴網頁，我現在要把我的帳號密碼輸入給伺服器呢？</p>
<p>因此，所謂的協議，其實就如同公文一般的存在。必須寫出特定的內容，讓兩邊的軟體知道你想要做什麼<br>
例如：</p>
<pre><code>    i want /index.html  
    字面上可能代表我要 index.html 這份檔案
</code></pre>
<p>我的伺服器程式只要做出分析字串的功能，當我看到 &quot;i want&quot; 就開始準備知道要把檔案抓出來準備送出。</p>
<p>接著又讀到一串文字 &quot;/index.html&quot; 就知道這個檔案是在哪個位置，然後送出去</p>
<p>但是又不能每個軟體都用自己的一套做法，不然我今天想做瀏覽器軟體，用的是 a 協議，另外一家用的是 b 協議。</p>
<p>因此，所謂的 http 協議就如此出現。</p>
<p>一個組織( w3c )來訂出軟體之間要如何獲取資料，因此剛剛的部份在 http 的協議就變成</p>
<pre><code>    GET /index.html HTTP/1.1 
    Host: www.example.org
    （GET 代表要一份檔案，後面則是接著檔案位置，
    最後一個 HTTP/1.1 則是代表這份公文使用的 http 第 1.1 版的協議。
    Host 則代表要跟哪台主機要檔案）
</code></pre>
<p>有了這種格式的公約，可以讓不同的軟體有辦法溝通，不管是伺服器、還是瀏覽器，只要有辦法生出同套體系的公文，</p>
<p>瀏覽器就有辦法在不同伺服器軟體之間索取檔案，伺服器也能傳送檔案給不同的瀏覽器。</p>
<p>當然，這協議的部份，一般的使用者跟網頁設計師是看不到的。瀏覽器跟伺服器軟體會讀取之後處理掉。</p>
<p>畢竟 html 內容才是使用者跟設計師需要在意的。</p>
<h5 id="">內容</h5>
<p>一般來說，網頁設計師在設計的內容，就是在這部份，大致分為 html 排版、css 美化、javascript 程式。</p>
<p>那這些內容最後都必須透過瀏覽器之間用協議溝通過，來索取內容的檔案。</p>
<p>因此跟伺服器索取完內容之後，伺服器大概會這樣回覆給瀏覽器</p>
<pre><code>    GET /index.html HTTP/1.1
    Host: www.example.org
    &lt;html&gt;
        &lt;head&gt;
            &lt;title&gt; Hello World &lt;/title&gt;
        &lt;/head&gt;
        &lt;body&gt;
            Welcome &lt;/br&gt;
        &lt;/body&gt;
    &lt;/html&gt;
</code></pre>
<p>瀏覽器會把前面那段協議的部份給砍掉，畢竟顯示畫面並不是靠那段協議，而是後面這段 html 的內容。</p>
<p>因此按 右鍵-&gt;檢視原始碼 時，並不會出現這種那段協議的文字。</p>
<h2 id="cookie">淺說 Cookie</h2>
<p>而現在要談到的事情就跟協議有很大一部分的關係。在寫有關網頁的程式，如果有仔細體會一下 php 的程式碼。<br>
如果我在 a.php 這個頁面宣告一個變數，到了下一頁 b.php ，這個變數就消失了。<br>
這一點不管是在 php 或是其他後端如 asp, jsp 甚至是前端的 js 都會出現這個狀況。</p>
<p>會發生這點主要的原因是因為當初 http 沒想這麼多，沒有在協議中規劃出這個方法，不過後來 http 協議當然有加上這功能了。 我們只要想辦法在協議的開頭中多出 Cookie 這東西，在瀏覽器跟伺服器之間就能之有個變數需要傳送來傳送去的。</p>
<pre><code>GET /index.php HTTP/1.1
Host: www.example.org
Cookie: 變數名稱=值  （多了這一欄來保留變數名稱跟變數的值）
</code></pre>
<p>因此，在瀏覽器跟伺服器之間保留變數的方式，就是透過協議的開頭來保留。我們只要想辦法讓伺服器或是瀏覽器，生出這段文字。<br>
軟體收到這樣的開頭就會知道現在有哪些變數正在互相傳遞。</p>
<p>所以不管是瀏覽器的 javascript 或是 php 都會提供 function 來保存 Cookie 變數。<br>
來稍微看一下 php 如何設定 cookie：</p>
<pre><code>PHP:
setcookie(account, 'FreedomKnight') // 如此一來就能生出一個 account 變數，
                                    // 內容為 FreedomKnight
</code></pre>
<p>這個 php 的 function 會生出一個 Set-Cookie 的一個 http 開頭</p>
<pre><code>Set-Cookie: account='FreedomKnight'
</code></pre>
<p>這跟剛剛的 Cookie 有點區別，Set-Cookie 的工作主要是通知瀏覽器，準備設定一個 account 變數。<br>
接著瀏覽器會把這變數存在用戶的電腦上面，下一次跟伺服器要 html 檔案的時候，開頭就會多出一段 Cookie<br>
告訴伺服器現在有哪些 Cookie 變數存在。</p>
<p>如果 php 要切換到下個頁面，要讀取 account 的值只需要</p>
<pre><code>$_COOKIE['account']
</code></pre>
<p>讀取 $_COOKIE 陣列，然後 php 會生出一個 $_COOKIE['account'] 欄位，從這裡抓取就行了。 有沒有發現 php 的 $_SERVER, $_COOKIE 幾乎都是處理 http 協議的東西，都從前頭那段，用特殊的陣列直接幫我們讀取好了。<br>
不用我們費心去做到把伺服器軟體給挖出來，叫 apache 還我們那段失去的開頭。</p>
<p>到此稍微總結一下 Cookie 的兩個主要的 http 格式</p>
<ol>
<li>Set-Cookie: 這一段是通知瀏覽器，請準備存放 Cookie 變數，下次記得通知伺服器有哪些 Cookie 變數存在。</li>
<li>Cookie: 每次都透過傳送 Cookie 來表示現在的連線有哪些 Cookie 變數</li>
</ol>
<p>因此，稍微仔細思考一下就能了解，為什麼常常會有要求 <code>setcookie</code> 之前不能有 html 的文字內容輸出了。<br>
因為 php 處理到 html 文字時，就得生出那段 http 協議的開頭了，這樣才能把內容接在協議後面給瀏覽器。<br>
所以必須特別小心 cookie 的這一點。</p>
<h2 id="session">開始談 Session</h2>
<p>剛剛談到的 Cookie ，瀏覽器跟為了能夠發送 Cookie 的 http 開頭，通常會把變數給存在使用者的電腦上，因此這樣就多了一分危險。<br>
php 考慮到這點之後，開始多做了一個機制，叫做 session 。<br>
但 session 也是靠著 cookie 去作到一件事情，把變數存放在伺服器這端。</p>
<p>php 會把變數放在伺服器的檔案中，然後給每個連線過來的瀏覽器一個流水號，叫做 session_id 。<br>
我們最多只透過 cookie 保存 session_id ，然後 php 會去找這個 id 的檔案，把變數抓出來。<br>
如此一來，可以降低 Cookie 被駭客抓到的風險，因為除了抓到 Cookie ，還得去伺服器才有辦法抓到變數的內容。</p>
<p>我們只要在 php 中</p>
<pre><code>$_SESSEION['account'] = 'FreedomKnight';
</code></pre>
<p>這段程式碼就會讓 php 開始工作，讓 http 協議開頭，多了一段 session_id ，並且另外開啟一個檔案來存放這個變數的內容。</p>
<pre><code>GET /index.php HTTP/1.1
Host: www.example.org
Cookie: PHPSESSID=0001
</code></pre>
<p>然後他就會在你的電腦上發現 sess_ 開頭的檔案，這些也就是用來放變數的檔案囉！</p>
<p>最後提到一點， session 跟 cookie 也一樣有相同的限制，就是不能在生出 html 之前就產出 session 變數。<br>
所以 php 多了幾個 function 幫助我們，讓我們可以無視這個規則。</p>
<pre><code>&lt;?php
session_start();
</code></pre>
<p>在開頭放上 session_start() 就能夠讓之後的內容都先不要產出 html 檔，等結束再一口氣送出，所以建議把 session_start() 放在檔案的最開頭。<br>
確保沒有任何 html 文字會生出，這些文字都會先放在 buffer 裡，最後在送出。</p>
<p>session 有這麼多好處，因此建議寫 php 的朋友可以使用 php 提供的 session 提高一點安全性。</p>
]]></content:encoded></item><item><title><![CDATA[javascript 匿名函數]]></title><description><![CDATA[<p>這幾年來，有個程式語言的名詞很夯，到處都在喊著 lambda, lambda, lambda ，就連 Java 下一次的改版重點也都放在 lambda 上面。<br>
而其中我最喜歡的語言 Python 也有這個東西，到底什麼是 lambda 呢？</p>
<p>其實 lambda 就是所謂的匿名函式，而其中的始祖就是 functional language 的始祖 - Lisp 所生出來的一個應用。<br>
對 js 而言，許多開發者也都不斷的嫌 js 奇怪、難用、噁心。但是仔細挖掘，會發現 functional language 才是 js 的根基。<br>
就連被詬病的 prototype 的物件導向，其實也很完美的應用了 functional 的思想。</p>
<p>這幾天我仔細挖掘之後才發現到 js</p>]]></description><link>https://fk.wtf/javascript-ni-ming-han-shu/</link><guid isPermaLink="false">5b91629ca7dce77ebd3443b1</guid><category><![CDATA[javascript]]></category><category><![CDATA[lambda]]></category><dc:creator><![CDATA[FreedomKnight]]></dc:creator><pubDate>Tue, 30 Sep 2014 06:02:00 GMT</pubDate><content:encoded><![CDATA[<p>這幾年來，有個程式語言的名詞很夯，到處都在喊著 lambda, lambda, lambda ，就連 Java 下一次的改版重點也都放在 lambda 上面。<br>
而其中我最喜歡的語言 Python 也有這個東西，到底什麼是 lambda 呢？</p>
<p>其實 lambda 就是所謂的匿名函式，而其中的始祖就是 functional language 的始祖 - Lisp 所生出來的一個應用。<br>
對 js 而言，許多開發者也都不斷的嫌 js 奇怪、難用、噁心。但是仔細挖掘，會發現 functional language 才是 js 的根基。<br>
就連被詬病的 prototype 的物件導向，其實也很完美的應用了 functional 的思想。</p>
<p>這幾天我仔細挖掘之後才發現到 js 的美，本篇會著重在 js 的匿名函式上。<br>
依照我的習慣，我一樣會先從原始的歷史來源介紹一下。</p>
<p>（以下所稱的「功能」、「函數」、「函式」，我都是指同一個東西 'function'）</p>
<ul>
<li>
<p>從 Lisp 開始(使用 Scheme)</p>
<p>我會大致上講一下 Lisp 主要的結構，不過只會講重點而已，大致上如下：</p>
<pre><code>(功能 參數1 參數2...) ; 分號開始是註解
                    ; 括號裡參數可以很多，端看功能需要幾個參數
</code></pre>
<p>一個正常的 lisp 一定是由一對括號組合起來。每個括號裡第一個參數代表的是你要做的功能 (function) ，緊跟著是這功能的參數。<br>
快速舉個例子：</p>
<pre><code>(+ 1 2)
</code></pre>
<p>對這一對括號來說，他的功能是 '+' 這個功能，當然就是加法啦！那他的功能就是把參數1 跟參數2 給加起來。<br>
這就是為甚麼叫做函數式語言的原因，所有的 Lisp 都是以這個為基礎。</p>
<ul>
<li>
<p>定義變數</p>
<p>來講講其中如何去定義一個變數。</p>
<pre><code>(define a 5) ; 使用 define 這個功能，其中第一個參數就是變數的名稱，第二個參數是他的值
</code></pre>
<p>很好理解吧？使用 define 就宣告出一個變數，當然重度的 Lisp 使用者會說不是如此，對 Lisp 而言只是把 a 跟 5 做個關係的相連而已。<br>
會用這麼繞口的方式講，是因為 define 也可以拿來定義一個功能、或者大家講的函數</p>
</li>
<li>
<p>定義函數</p>
<pre><code>(define (add x y) (+ x y)) ; 第一個參數是這個功能的名字和參數、第二個參數則是主體
以下為使用 add：
(add 1 2) ; 螢幕上會顯示回傳 3 這個數字
</code></pre>
<p>看了這個例子就是前面為什麼要做特別補充了，因為第一個參數可以不只是單一個變數名稱，也可以是以一個括號定義一個函數（功能）的名稱以及參數，第二個參數也是用括號去定義一個要如何執行的本體。</p>
<p>因此對於 define 來說，他個功能真的可以總結為把兩者的關係相連。</p>
<pre><code>(define 名稱 對象) ; 名稱 -&gt; 對象
</code></pre>
</li>
</ul>
</li>
<li>
<p>Lisp 的匿名函數</p>
<p>剛剛講了這麼多，單純只是為了匿名函數去做鋪陳，因為我也想讓沒學過 Lisp 的人了解這一層關係。<br>
在 Lisp 中，宣告函式也是可以不必去宣告名稱的，只需要使用 lambda 這個功能，他就能幫你把一個沒有名字的函數宣告出來。</p>
<pre><code>(lambda (參數) (函數的主體))
ex.
(lambda (x y) (+ x y))
</code></pre>
<p>如此一來，就有一個需要參數為 x 跟 y 的加法函數出來，但是目前這意義不大，因為不知道這家伙的名字，無法去呼叫這功能<br>
像剛剛還有辦法 <code>(add 1 2)</code> ，現在則是無從呼叫起</p>
<p>但是剛剛有說過 define 可以連結一個名稱，我們可以試著:</p>
<pre><code>(define add (lambda (x y) (+ x y)))
以下執行：
(add 1 2) ;螢幕上會顯示 3 這個結果
</code></pre>
<p>這跟宣告函數的方式根本就是同一個效果，只是剛剛是把函數的形體（名稱、參數），對主體（+ x y ）做結合<br>
而這次是宣告一個名稱為 add 的變數去跟後面的沒有名稱的函數做連結<br>
各位應該還是覺得很白痴，為什麼同樣的事情要分兩種方法？<br>
除了意義上的不同， lambda 還能這樣做：</p>
<pre><code>((lambda (x y) (+ x y)) 1 2) ;螢幕也會顯示結果為 3
</code></pre>
<p>這就是 lambda 的妙用呀！還記得剛剛我說過，Lisp 的主軸是 <code>(功能 參數1 參數 2)</code> 吧？<br>
對最外頭的括號來說，拆了三個部份 <code>(lambda (x y) (+ x y))</code>, <code>1</code>, <code>2</code> 那個 lambda 就是功能的部份，接著這個括號會把 1 跟 2 丟下去算</p>
<p>算完之後，就再也無法呼叫這個臨時做出來的加法功能了。因為他根本沒有名字，無從呼叫起呀！<br>
對一個好的直譯器來說，就會把他回收掉了。lambda 除了可以省記憶體之外，也能節省取名稱這件事。</p>
<p>Python 中也已經導入 lambda 這功能了，很多 GUI 的功能你並不想取名字，也能直接與像是按鈕事件結合 有興趣可以參考一下我的 <a href="http://blog-freedomknight.rhcloud.com/python-counter/">心理測驗計數器</a></p>
</li>
<li>
<p>完美結合 functional language 的 js</p>
<p>如同我一開始所說，許多人誤解 js 醜陋，是因為並不了解 functional language 。對 js 而言，他是使用像是 ALGOL 系語言的方式去宣告函數，而不是用括弧海並且把函數的名稱放在括弧內。</p>
<p>基本的 function 宣告方式</p>
<pre><code>function add(x, y) {
    return x + y;
}
</code></pre>
<p>如此一來下次就能以 <code>add(1, 2)</code> 的方式呼叫加法的函數了<br>
對於 js 而言，他也能像剛剛 Lisp 那樣，可以宣告一個匿名函數跟變數名稱結合</p>
<pre><code>var add = function(x, y) {
    return x + y;
 }; // 這裡有分號，是因為把他當正常的運算把值丟給變數，事實上 EMCAScript 並沒有強求分號
</code></pre>
<p>這樣做除了是把 add 變數跟一個沒有名字的 function 結合之外，兩者最大的不同點在於，前者會先被直譯器給挖出來。 因此前者可以：</p>
<pre><code>add(1, 2);
function add(x, y) {
    return x, y;
}
</code></pre>
<p>因為前者會被挖出來之後，就一直在電腦裡面，等待其他人的呼叫。而使用後者將變數接上匿名函數，則像是當個基礎的運算。<br>
執行到 <code>var add = function(x, y) {...}</code> 這一行，才開始把這個函數的形體給準備好，丟給 add 這個變數。</p>
<p>也因為這個特性，除了省空間，也多了彈性：</p>
<pre><code>var op = function(x, y) {
    return x + y;
};
op(1, 2); // 會回傳 3

var op = function(x, y) {
    reutrn x - y;
};
op(5, 1); // 會回傳 4
</code></pre>
<p>用變數這種方法去接上匿名函數，可以很彈性的切換 function 。<br>
接著匿名函式還有最經典，但是常常會弄得讓人沒有頭緒的樣貌。</p>
<pre><code>(function(x, y) {
     return x + y;
})(1, 2);
</code></pre>
<p>這答案一樣會回傳 1 + 2 的加法結果 3 ，那這個樣貌的匿名函式要如何看起呢？</p>
<pre><code>呼叫 function 的一般樣貌：
函數(參數1, 參數2);
</code></pre>
<p>這是我們一般呼叫 js 函數的方法，也就是說，對這個例子來說，那個匿名函式就是我們的主體。<br>
那為什麼需要前面的小括弧呢？如果沒有那個小括號，他就像是最一開始的宣告函數的樣子，直譯器期待你宣告一個函數的名稱。<br>
而小括號對 js 來講，算是個強迫運算，像我們平時運算 <code>(2 + 3) * 5</code> 會用小括號先強迫把 2 + 3 算出來。</p>
<p>對這個小括弧而言，則是強迫生出個匿名函數並且呼叫</p>
<pre><code>具有名稱時我們是如此呼叫：
add(1, 2);

現在是匿名函數:
(匿名函數)(1, 2);
</code></pre>
<p>其實形式上還是一樣，單純只是變形的呼叫。這時使用匿名的最大大大優點就是「船過水無痕」。 任何你在裡頭做的事情，所佔的任何空間，到最後會馬上釋放。<br>
在小型 js 看不出來，但是再大型一點的程式，大家一股腦的宣告了一堆全域函數跟變數，如果瀏覽器還沒離開這個頁面，這些空間就一直被佔著，無法釋放。</p>
<p>如果有同好有去看一下 jQuery 的原始碼，在前幾行就會看到這神奇的樣式了。</p>
</li>
<li>
<p>總結</p>
<p>其他說要導入 lambda 的語言，幾乎都會將 lambda 這個 keyword 抓進來，而對 js 而言則是完全不留痕跡的將這個 lambda 的特性導入，除了 lambda 這特性之外，就連物件導向也是利用函數式語言的方式去做到，並且完全不強求括弧海，完全是用大家最熟悉的 ALGOL 系語言去達成。</p>
<p>總而言之，js 事實上是個優美的變形蟲，需要深入去了解才能體會他的美。未來等我研究更仔細的物件導向會在跟大家分享 js 的 OO。</p>
</li>
</ul>
]]></content:encoded></item></channel></rss>