<?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"><channel><title><![CDATA[Mostly Functional]]></title><description><![CDATA[/\.(ex|jsx?|rb|hs|rs|py)/, A father, a bookworm, a pluviophile. Co-organizer of http://Elixir.tw. Learning Satir, coaching & mediation.]]></description><link>https://taian.su</link><generator>RSS for Node</generator><lastBuildDate>Sun, 12 Apr 2026 22:56:13 GMT</lastBuildDate><atom:link href="https://taian.su/rss.xml" rel="self" type="application/rss+xml"/><language><![CDATA[en]]></language><ttl>60</ttl><item><title><![CDATA[Handling N-dimensional Lists in Elixir with Ndim]]></title><description><![CDATA[Process the n-dimensional list
In data processing and numerical computing, operations on n-dimensional lists are common. These nested data structures represent matrices, tensors, and other multi-dimensional arrays. Here's an example of such structure...]]></description><link>https://taian.su/handling-n-dimensional-lists-in-elixir-with-ndim</link><guid isPermaLink="true">https://taian.su/handling-n-dimensional-lists-in-elixir-with-ndim</guid><category><![CDATA[Elixir]]></category><category><![CDATA[Functional Programming]]></category><category><![CDATA[Haskell]]></category><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Thu, 12 Dec 2024 08:18:06 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-process-the-n-dimensional-list">Process the n-dimensional list</h2>
<p>In data processing and numerical computing, operations on n-dimensional lists are common. These nested data structures represent matrices, tensors, and other multi-dimensional arrays. Here's an example of such structures:</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># 2 dimensional list (matrix)</span>
[
  [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>],
  [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]
]
</code></pre>
<p>As an elixir alchemist, use <a target="_blank" href="http://Enum.map/2"><code>Enum.map/2</code></a> to transform lists is our second nature. However, when dealing with nested lists, transforming elements at specific depths requires multiple nested mapping operations. Consider these approaches:</p>
<pre><code class="lang-elixir">[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]
|&gt; Enum.map(<span class="hljs-keyword">fn</span> row -&gt;
     Enum.map(row, <span class="hljs-keyword">fn</span> i -&gt;
       i * <span class="hljs-number">10</span>
     <span class="hljs-keyword">end</span>)
   <span class="hljs-keyword">end</span>)

<span class="hljs-comment">#=&gt; [[10, 20], [30, 40]]</span>
</code></pre>
<p>When working with three or higher dimensional lists, the complexity of operations increases significantly:</p>
<pre><code class="lang-elixir">[
  [
    [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>]
  ],
  [
    [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]
  ]
]
|&gt; Enum.map(<span class="hljs-keyword">fn</span> row -&gt;
     Enum.map(<span class="hljs-keyword">fn</span> column -&gt;
       Enum.map(<span class="hljs-keyword">fn</span> i -&gt;
        i * <span class="hljs-number">10</span>
       <span class="hljs-keyword">end</span>)
     <span class="hljs-keyword">end</span>)
<span class="hljs-keyword">end</span>)
</code></pre>
<h2 id="heading-function-lifting-through-functors-in-haskell"><strong>Function Lifting</strong> through Functors in Haskell</h2>
<p>In Haskell, a lazy evaluation functional programming language, lists implement the Functor typeclass. This allows us to 'lift' functions that work on single values into a function works on lists, using <code>fmap</code>.</p>
<p>For example, if we have a function <code>(+ 1)</code> that adds 1 to a single number, <code>fmap (+ 1)</code> lifts this function to work on an entire list of numbers, transforming each element. This is conceptually similar to <a target="_blank" href="http://Enum.map/2"><code>Enum.map/2</code></a> in Elixir.</p>
<p>And the key feature of function lifting is its composability through functor composition. Consider how the same function can be lifted to operate on increasingly nested structures:</p>
<pre><code class="lang-haskell"><span class="hljs-comment">-- Function operating on a single value</span>
(+ <span class="hljs-number">1</span>) <span class="hljs-number">1</span>
<span class="hljs-comment">--&gt; 2</span>

<span class="hljs-comment">-- Function lifted to operate on a list (1-dimensional)</span>
<span class="hljs-title">fmap</span> (+ <span class="hljs-number">1</span>) [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>]
<span class="hljs-comment">--&gt; [2, 3]</span>

<span class="hljs-comment">-- Function lifted to operate on a nested list (2-dimensional)</span>
(fmap . fmap) (+ <span class="hljs-number">1</span>) [[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]
<span class="hljs-comment">--&gt; [[2, 3], [4, 5]]</span>

<span class="hljs-comment">-- Function lifted to operate on a doubly nested list (3-dimensional)</span>
(fmap . fmap . fmap) (+ <span class="hljs-number">1</span>) [[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]], [[<span class="hljs-number">5</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">7</span>, <span class="hljs-number">8</span>]]]
<span class="hljs-comment">--&gt; [[[2, 3], [4, 5]], [[6, 7], [8, 9]]]</span>
</code></pre>
<p>The composition of <code>fmap</code> with itself <code>(fmap . fmap)</code> allows us to reach deeper into nested structures while preserving their dimensionality. Each additional composition of <code>fmap</code> adds another level of penetration into the nested structure.</p>
<h2 id="heading-using-kernelgetin3">Using <code>Kernel.get_in/3</code></h2>
<p>In Elixir, we can achieve similar behavior using <code>Kernel.update_in/3</code> with <code>Access.all/1</code>. This approach allows us to traverse and transform nested lists at specific depths:</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># list</span>
[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>] |&gt; update_in([Access.all()], &amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>)) <span class="hljs-comment">#=&gt; [2, 3]</span>

<span class="hljs-comment"># 2 dimensional list</span>
[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]] |&gt; update_in([Access.all(), Access.all()], &amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>))
<span class="hljs-comment">#=&gt; [[2, 3], [4, 5]]</span>

<span class="hljs-comment"># 3 dimensional list</span>
[[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]], [[<span class="hljs-number">5</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">7</span>, <span class="hljs-number">8</span>]]]
|&gt; update_in([Access.all(), Access.all(), Access.all()], &amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>))
<span class="hljs-comment">#=&gt; [[[2, 3], [4, 5]], [[6, 7], [8, 9]]]</span>
</code></pre>
<p>While this approach works, it requires repetitive use of <code>Access.all()</code> for each level of nesting, making it syntactically verbose.</p>
<h2 id="heading-dimensional-mapping-with-ndim">Dimensional Mapping with Ndim</h2>
<p>The <code>Ndim</code> library, named for its ability to handle n-dimensional lists, provides a more concise syntax for transforming nested lists. It offers both dimension-specific functions and a general-purpose mapping function:</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># Transform elements in a 2-dimensional list</span>
[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]
|&gt; Ndim.d2map(&amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>))
<span class="hljs-comment">#=&gt; [[2, 3], [4, 5]]</span>

<span class="hljs-comment"># Transform elements in a 3-dimensional list</span>
[[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]], [[<span class="hljs-number">5</span>, <span class="hljs-number">6</span>], [<span class="hljs-number">7</span>, <span class="hljs-number">8</span>]]]
|&gt; Ndim.d3map(&amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>))
<span class="hljs-comment">#=&gt; [[[2, 3], [4, 5]], [[6, 7], [8, 9]]]</span>
</code></pre>
<p>In addition to the dimension-specific functions (<code>d2map/2</code> through <code>d5map/2</code>), <code>Ndim</code> provides a general-purpose <code>dmap/3</code> that can operate on lists of any dimension:</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># Transform elements at any specified dimension</span>
nested_list |&gt; Ndim.dmap(dimension, transformation_function)

<span class="hljs-comment"># Example: Transform a 6-dimensional list</span>
deeply_nested_list |&gt; Ndim.dmap(<span class="hljs-number">6</span>, &amp;(&amp;<span class="hljs-number">1</span> + <span class="hljs-number">1</span>))
</code></pre>
<h2 id="heading-converting-n-dimensional-lists-to-coordinate-maps">Converting N-dimensional Lists to Coordinate Maps</h2>
<p>The Ndim library also provides functionality to transform n-dimensional lists into coordinate maps, where each value is keyed by its dimensional coordinates. Currently supports 2-dimensional and 3-dimensional structures:</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># Converting a 2-dimensional list to a coordinate map</span>
[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>], [<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]
|&gt; Ndim.to_coordinate_map()
<span class="hljs-comment">#=&gt; %{{0, 0} =&gt; 1, {0, 1} =&gt; 2, {1, 0} =&gt; 3, {1, 1} =&gt; 4}</span>

<span class="hljs-comment"># Converting a 3-dimensional list to a coordinate map</span>
[[[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>]], [[<span class="hljs-number">3</span>, <span class="hljs-number">4</span>]]]
|&gt; Ndim.to_coordinate_map()
<span class="hljs-comment">#=&gt; %{{0, 0, 0} =&gt; 1, {0, 0, 1} =&gt; 2, {1, 0, 0} =&gt; 3, {1, 0, 1} =&gt; 4}</span>
</code></pre>
<p>This coordinate mapping is particularly useful for:</p>
<ul>
<li><p>Sparse matrix operations</p>
</li>
<li><p>Direct coordinate-based access</p>
</li>
<li><p>Grid-based calculations</p>
</li>
</ul>
<hr />
<p>Hope you like it, and happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[聊聊 Elixir 中的 type]]></title><description><![CDATA[最近有幾位朋友分別來問 Elixir 的 type 的問題，想說中文世界好像沒有比較完整的東西，就把知道的東西整理出來。

(目前) Elixir 的 type 能做什麼？
tl;dr: 最主要是文件，然後在某種程度下防止錯誤。
我覺得這應該是在研究 Elixir 的 type 時最需要知道的事情了。不像 Haskell 及 F# 這種以型別著稱的 ML 系語言，Elixir / Erlang 本質上是個動態語言，所有與型別有關的標註都會被編譯器忽略。而 Erlang 內建的型別檢查工具 dia...]]></description><link>https://taian.su/2022-10-18-type-in-elixir</link><guid isPermaLink="true">https://taian.su/2022-10-18-type-in-elixir</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Tue, 18 Oct 2022 16:57:56 GMT</pubDate><content:encoded><![CDATA[<p>最近有幾位朋友分別來問 Elixir 的 type 的問題，想說中文世界好像沒有比較完整的東西，就把知道的東西整理出來。</p>

<h2 id="heading-elixir-type">(目前) Elixir 的 type 能做什麼？</h2>
<p>tl;dr: 最主要是文件，然後在某種程度下防止錯誤。</p>
<p>我覺得這應該是在研究 Elixir 的 type 時最需要知道的事情了。不像 Haskell 及 F# 這種以型別著稱的 ML 系語言，Elixir / Erlang 本質上是個動態語言，所有與型別有關的標註都會被編譯器忽略。而 Erlang 內建的型別檢查工具 dialyzer 是採用 success typing，在型別 <em>有可能</em> 是正確的時候就視為通過 (等一下會看到有趣的範例)，所以目前在 Elixir 中撰寫型別標注最主要還是用做於程式相互操作間的文件溝通使用。</p>
<p>我自己個人的習慣通常是剛開始寫 code 時不會標注型別，然後在寫測試程式時把 public 的函式都標上型別。當然也有專注在資料結構的情況，這時候才會一開始就對型別比較講究。</p>
<h2 id="heading-elixir">Elixir 的型別標注語法</h2>
<p>Elixir 的型別語法主要就看官方文件的 <a target="_blank" href="https://hexdocs.pm/elixir/1.12/typespecs.html">typespecs 這一頁</a>。比較值得另外提的就是 sum type (union type) 跟 product type 的標記方式。在 Elixir 裡 sum type 是用 <code>|</code> 這個符號來分隔。而 product type 就是用 tuple 語法了。來個範例：</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">Card</span></span> <span class="hljs-keyword">do</span>
  <span class="hljs-comment"># 自定義的型別用 @type</span>
  <span class="hljs-comment"># 四種 atom 中的一種</span>
  <span class="hljs-variable">@type</span> suit() :: <span class="hljs-symbol">:clubs</span> | <span class="hljs-symbol">:diamonds</span> | <span class="hljs-symbol">:hearts</span> | <span class="hljs-symbol">:spades</span>

  <span class="hljs-comment"># 2 到 10 的數字或是四種 atom 中的一種</span>
  <span class="hljs-variable">@type</span> rank() :: <span class="hljs-number">2</span>..<span class="hljs-number">10</span> | <span class="hljs-symbol">:jack</span> | <span class="hljs-symbol">:queen</span> | <span class="hljs-symbol">:king</span> | <span class="hljs-symbol">:ace</span>

  <span class="hljs-comment"># product type 用 {}</span>
  <span class="hljs-comment"># t 表示 Remote type。這個會變成 Card module 本身的 type，</span>
  <span class="hljs-comment"># 可以用 Card 或是 Card.t() 來指涉這個型別</span>
  <span class="hljs-variable">@type</span> t :: {rank(), suit()}

  <span class="hljs-comment"># 標注函式型別用 spec</span>
  <span class="hljs-comment"># 接收 list of cards, 回傳 card</span>
  <span class="hljs-variable">@spec</span> deal([Card]) :: Card
  <span class="hljs-comment"># 同一個模組下也可以直接用 t 表示，改成這樣：</span>
  <span class="hljs-comment"># @spec deal([t]) :: t</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">deal</span></span>(cards) <span class="hljs-keyword">do</span>
    <span class="hljs-comment"># not implement yet</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>
</code></pre>
<h2 id="heading-type">比較有用/有趣的內建 type</h2>
<p>數字的話有 <code>neg_integer()</code>、<code>non_neg_integer()</code> 跟 <code>pos_integer()</code> 可以用。</p>
<p>高階函式可以用 <code>(type1 -&gt; type2)</code> 等箭號系列當做參數或是回傳值的型別標注。</p>
<p>有 <code>nonempty_list</code> 表示不為空的串列，跟 <code>maybe_improper_list</code>，用來表示中間階段，其結尾還不是 <code>[]</code> 的 list，那麼就有延伸的 <code>nonempty_improper_list</code>、<code>nonempty_maybe_improper_list</code></p>
<p>在 map 的部份可以做出非常細緻的定義，需要有什麼 key，對應的值的型別是什麼，還有可以有 optional 的選項。這些就請看文件了。</p>
<p><code>mfa</code> 代表 <code>{module, funciton_name, arity}</code> 的 tuple，這個在做 meta-programming 的時候蠻好用的。</p>
<h2 id="heading-5yw25a6d55qe5qiz6ki75bgs5ocn">其它的標註屬性</h2>
<p><code>@typep</code> 用來表示這個自定義的型別只在目前的 module 中可見，而 <code>@opaque</code> 則是外界看得到這個型別，但是無法知道裡面的結構。</p>
<p>而 <code>@callback</code> 跟 <code>@macrocallback</code> 則是在操作 Behaviour 的時候使用的，常見的情況就是在實作 GenServer 或其它的 Behaviour 時，標註 <code>@callback</code> 就會幫你檢查是否所需要的 callback 都有妥善的依規格實作。</p>
<h2 id="heading-success-typing">Success typing 是什麼</h2>
<p>我們來寫一個 compare 的例子，給兩張牌，回傳第一張跟第二張相比的大小。</p>
<pre><code class="lang-elixir"><span class="hljs-variable">@spec</span> compare(Card, Card) :: <span class="hljs-symbol">:gt</span> | <span class="hljs-symbol">:eq</span> | <span class="hljs-symbol">:lt</span>
<span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">compare</span></span>(_c1, _c2) <span class="hljs-keyword">do</span>
  <span class="hljs-string">"opps"</span>
<span class="hljs-keyword">end</span>
</code></pre>
<p>在無視輸入直接回傳一個錯誤的型別， 如果你的編輯器有裝 language server protocol，那麼就會跳出有問題的提示：</p>
<p><img src="uploads/2022/47762f8538.png" alt="Wrong spec" /></p>
<p>或是你也可以在 project 中安裝 <a target="_blank" href="https://github.com/jeremyjh/dialyxir">dialyxir</a>，這是 Erlang 內建的型別檢查工具 dialyzer (唸 di-a-lai-zer) 的 wrapper，按其說明 compile 並執行，就會開心的看到如下的錯誤訊息：</p>
<p><img src="uploads/2022/9c692aa581.png" alt="Dialyzer error" /></p>
<p>那麼把型別改成正確的回傳就沒問題了：</p>
<p><img src="uploads/2022/df28e3b443.png" alt="Type correct" /></p>
<p>那如果不是固定的值，而是計算的結果呢？回傳 <code>1 + 1</code>，一樣可以看到型別錯誤的提示。</p>
<p><img src="uploads/2022/e256aaed6c.png" alt="Calc type error" /></p>
<p>不過我們高興的太早了。如果我們這樣寫的話， success typing 會認為這段程式碼是 <em>合法的</em>。</p>
<p><img src="uploads/2022/4a2bd0026c.png" alt="wat" /></p>
<p>原因是因為雖然"我們"知道這段程式碼只會回傳 "wat" 字串，但是 Elixir 不知道。在型別檢查階段，只能確認 <code>Enum.random/1</code> 函式的回傳型別是 <code>any()</code>，所以 dialyzer 覺得呼叫 <code>Enum.random/1</code> 回傳 <code>:eq | :gt | :lt</code> 其中一個的機率不為零，所以就放行了…這段程式碼只接收了 list of string 的這個事實，要到編譯階段才會知道，但那時型別標注都已經被移掉了。</p>
<p>看到這裡應該就可以理解為什麼 Elixir / Erlang dev 一直以來沒有非常認真的看待 type 的原因了。</p>
<h2 id="heading-6yke5pyj5lia5lqb5yw25a6d55qe">還有一些其它的</h2>
<p>不過只要是會長期維護的專案，我個人的習慣還是都會加上 dialyxir 並設到 CI 裡。經驗上我還是有好幾次在修改了程式碼後，unit test 通過但是型別檢查噴了錯誤訊息救到我的案例出現。</p>
<p>而在社群的關注下， José Valim 在 ElixirConf EU 2022 講了很久的 typing 的議題，也宣布了有想要朝 gradual typing 進行認真的研究的方向。在上個月也在官網發了文章把 talk 的內容匯整起來：</p>
<p><a target="_blank" href="https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types">https://elixir-lang.org/blog/2022/10/05/my-future-with-elixir-set-theoretic-types/</a></p>
<p>不過官方目前的態度是不知道這個研究會產生什麼結果，所以也只能等著看看了…</p>
]]></content:encoded></item><item><title><![CDATA[Elixir.tw online meetup 指南]]></title><description><![CDATA[Meetup 形式與主題
每次預計 45min ~ 1hr 主題 talks, 另外有 30min 左右的發問與閒聊時間。而每次聚會的talks 部份會測錄並上線。


2020/04/14 Elixir 基本語法
2020/05/12 Phoenix

其它主題(日期與形式規劃中)

進階語法
macro
Phoenix LiveView & Channel
Concurrent, OTP & Flow
Ecto
ETS
Nerves
deployment
rustler

事前準備
線上 m...]]></description><link>https://taian.su/2020-04-05-elixirtw-online-meetup</link><guid isPermaLink="true">https://taian.su/2020-04-05-elixirtw-online-meetup</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Sat, 04 Apr 2020 18:00:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-meetup">Meetup 形式與主題</h2>
<p>每次預計 45min ~ 1hr 主題 talks, 另外有 30min 左右的發問與閒聊時間。而每次聚會的talks 部份會測錄並上線。</p>

<ul>
<li>2020/04/14 Elixir 基本語法</li>
<li>2020/05/12 Phoenix</li>
</ul>
<h3 id="heading-5yw25a6d5li76agmkoaxpeacniihw9ouw8jimjwkgs4rsk">其它主題(日期與形式規劃中)</h3>
<ul>
<li>進階語法</li>
<li>macro</li>
<li>Phoenix LiveView &amp; Channel</li>
<li>Concurrent, OTP &amp; Flow</li>
<li>Ecto</li>
<li>ETS</li>
<li>Nerves</li>
<li>deployment</li>
<li>rustler</li>
</ul>
<h2 id="heading-5lql5ymn5rqw5ykz">事前準備</h2>
<p>線上 meetup 將使用 Google Hangout Meeting，並用 Visual Studio Code 的 LiveShare 功能輔助。另外我們建議在你的電腦上安裝好 Elixir 的開發環境。</p>
<ul>
<li><a target="_blank" href="https://gsuite.google.com.tw/intl/zh-TW/products/meet/">Google Hangouts Meet：線上視訊會議服務</a> (需要有 Google 帳號)</li>
<li><p><a target="_blank" href="https://marketplace.visualstudio.com/items?itemName=MS-vsliveshare.vsliveshare-pack">Live Share Extension Pack</a> (需先安裝 Visual Studio Code)</p>
</li>
<li><p><a target="_blank" href="https://taian.su/2019-06-13-elixir-env/">Elixir 環境安裝指南</a></p>
</li>
</ul>
<h2 id="heading-5pwz5p2q">教材</h2>
<p>若你對 Elixir 語法還不熟悉，建議你可以用 <a target="_blank" href="https://elixirschool.com/zh-hant/">Elixir School</a> 的教學做為參考。第一次講解的內容基本上涵蓋該教材基礎部份的 1 ~ 7 章。</p>
<h2 id="heading-5yw25a6d">其它</h2>
<p>若你有任何想要分享的主題或是特別感興趣的方向，歡迎在 <a target="_blank" href="https://www.facebook.com/groups/elixir.tw">Facebook 粉絲團</a>，Slack，或來信 ask@elixir.tw 與我們討論。</p>
<hr />
<h2 id="heading-elixir">Elixir 能用來做什麼，好處在哪？</h2>
<ul>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=lxYFOM3UJzo">Elixir: The Documentary - YouTube</a> (翻譯中)</p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=JvBT4XBdoUE">GOTO 2019 • The Soul of Erlang and Elixir • Saša Jurić - YouTube</a> (翻譯中)</p>
</li>
<li><p><a target="_blank" href="https://www.youtube.com/watch?v=Z2DU0qLfPIY">ElixirConf 2018 - Keynote - Chris McCord - YouTube</a></p>
</li>
</ul>
<h2 id="heading-elixr-erlang">誰在用 Elixr (或它的底層： Erlang)</h2>
<h3 id="heading-elixir-1">Elixir:</h3>
<ul>
<li>Discord</li>
<li>Pinterest</li>
<li>Moz</li>
<li>Toyota Connected</li>
<li>Grinder</li>
<li>怪物彈珠</li>
<li>任天堂</li>
</ul>
<h3 id="heading-erlang">Erlang</h3>
<ul>
<li>Ericsson</li>
<li>WhatsApp</li>
<li>RabbitMQ</li>
<li>Riak</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[Steam 上的程式教學類遊戲]]></title><description><![CDATA[農曆年期間比較有空，玩了一些之前買的遊戲。這次特別試了幾個標榜讓不會寫程式的人學寫程式的遊戲。分享一下試玩的心得。

1. 7 Billion Humans
考慮到劇情的話我最喜歡的是 7 Billion Humans。它用拖拉語法的方式下指令，一開始還蠻好上手的，但是因為只有 goto 那樣的結構，而操作的時候又是一次對所有的 worker 下指令，所以常常要想一下執行後每個人運作的順序。但是介面有正體中文，以「想要體驗一下寫程式大概是怎麼一回事」來說還蠻適合的。


2. while Tru...]]></description><link>https://taian.su/2020-02-25-programming-games-on-steam</link><guid isPermaLink="true">https://taian.su/2020-02-25-programming-games-on-steam</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Mon, 24 Feb 2020 23:00:00 GMT</pubDate><content:encoded><![CDATA[<p>農曆年期間比較有空，玩了一些之前買的遊戲。這次特別試了幾個標榜讓不會寫程式的人學寫程式的遊戲。分享一下試玩的心得。</p>

<h2 id="heading-1-7-billion-humans">1. 7 Billion Humans</h2>
<p>考慮到劇情的話我最喜歡的是 7 Billion Humans。它用拖拉語法的方式下指令，一開始還蠻好上手的，但是因為只有 goto 那樣的結構，而操作的時候又是一次對所有的 worker 下指令，所以常常要想一下執行後每個人運作的順序。但是介面有正體中文，以「想要體驗一下寫程式大概是怎麼一回事」來說還蠻適合的。</p>
<iframe src="https://store.steampowered.com/widget/792100/" width="646" height="190"></iframe>

<h2 id="heading-2-while-true-learn">2. while True: learn()</h2>
<p>這個遊戲說的是某個 programmer 發現他的貓會寫程式，所以要開發一個喵語翻譯器。想要模擬的是機器學習的內容，所以是試著組合各種過濾器(神經網路？)。因為精度高的過濾器慢加上有時間限制，所以習慣找最簡單的組合的想法常常會超時，手感跟 deterministic algorithm 差很多。也有正體中文介面不過有些翻譯怪怪的。</p>
<iframe src="https://store.steampowered.com/widget/619150/?t=%E4%BD%A0%E6%98%AF%E4%B8%80%E5%80%8B%E5%AF%AB%E7%A5%9E%E7%B6%93%E7%B6%B2%E7%B5%A1%E7%9A%84%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92%E5%B0%88%E5%AE%B6%EF%BC%8C%E4%BD%86%E6%98%AF%E4%BD%A0%E5%AE%B6%E8%B2%93%E4%B8%BB%E5%AD%90%E8%B2%8C%E4%BC%BC%E6%AF%94%E4%BD%A0%E8%A6%81%E5%8E%B2%E5%AE%B3%E5%95%8A%E3%80%82%E6%89%80%E4%BB%A5%E7%8F%BE%E5%9C%A8%E4%BD%A0%E5%BF%85%E9%A0%88%E8%A6%81%E8%A7%A3%E6%B1%BA%E5%90%84%E7%A8%AE%E9%9B%A3%E9%A1%8C%E4%BE%86%E5%89%B5%E5%BB%BA%E4%B8%80%E6%AC%BE%E8%B2%93%E8%AA%9E%E7%BF%BB%E8%AD%AF%E5%99%A8%EF%BC%88%E8%AA%B0%E7%9F%A5%E9%81%93%E4%BD%A0%E5%AE%B6%E4%B8%BB%E5%AD%90%E9%82%84%E6%9C%83%E5%B9%B9%E4%BB%80%E9%BA%BC%E5%91%A2%EF%BC%89%EF%BC%81%E8%B3%BA%E9%8C%A2%EF%BC%8C%E7%B5%A6%E8%B2%93%E4%B8%BB%E5%AD%90%E8%B2%B7%E9%A3%BE%E5%99%A8%EF%BC%8C%E7%9E%AD%E8%A7%A3%E7%9C%9F%E6%AD%A3%E7%9A%84%E6%A9%9F%E5%99%A8%E5%AD%B8%E7%BF%92%E7%9A%84%E5%A7%BF%E5%8B%A2%EF%BC%81" width="646" height="190"></iframe>

<h2 id="heading-3-grey-hack">3. Grey hack</h2>
<p>這個遊戲打開就是一付 Linux 樣，有瀏覽器，郵件軟體跟終端機，然後就要去接任務 hack 東西，也可以寫 script。基本上沒什麼「我在玩遊戲」的感覺，往好處來說就是 context switch 成本很小？ (不是</p>
<p>不過我還蠻喜歡的。</p>
<iframe src="https://store.steampowered.com/widget/605230/" width="646" height="190"></iframe>

<h2 id="heading-4-screeps">4. Screeps</h2>
<p>Screeps 就要真的寫程式碼了。這個遊戲用 JavaScript 操作，玩類似 starcraft 般的遊戲。所以對程式完全陌生的人應該會蠻辛苦了。一開始的 tutorial 蠻簡單，但是每次都帶上文件連結，「我還是在寫程式啊」的感覺比上個遊戲更強烈。還好我就是愛寫程式。愛就是愛。 XD</p>
<iframe src="https://store.steampowered.com/widget/464350/110423/" width="646" height="190"></iframe>


<hr />
<p>其它看起來比較有趣但是還沒有買的有 <a target="_blank" href="https://store.steampowered.com/app/300570/Infinifactory/">Infinifactory</a> 、<a target="_blank" href="https://store.steampowered.com/app/558990/Opus_Magnum/">Opus Magnum</a> 跟 <a target="_blank" href="https://store.steampowered.com/app/990900/Neon_Noodles__Cyberpunk_Kitchen_Automation/">Neon Noodles</a></p>
]]></content:encoded></item><item><title><![CDATA[Let's (re)start from here.]]></title><description><![CDATA[最近的時間大半都花在這上面了。
算算應該是第五次弄部落格系統。算一下扣除上古時期用現成的之外，每個系統平均各寫六篇文章，也都撐不過兩年。前幾個分別用了 Refinery CMS -> jekyll -> middleman -> jekyll。想來架系統的總時數應該超過寫文章的時間 XD

而這次用上了 Gatsby +
tailwindcss，除了恢復一下 GraphQL
的手感之外，這次還挑戰了不套別人做的版型，自己把類似上一個部落格的 style 刻出來。想說來分享一下這些技術的感想：
G...]]></description><link>https://taian.su/2020-01-11-lets-restart-from</link><guid isPermaLink="true">https://taian.su/2020-01-11-lets-restart-from</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Sat, 11 Jan 2020 03:12:00 GMT</pubDate><content:encoded><![CDATA[<p>最近的時間大半都花在這上面了。</p>
<p>算算應該是第五次弄部落格系統。算一下扣除上古時期用現成的之外，每個系統平均各寫六篇文章，也都撐不過兩年。前幾個分別用了 Refinery CMS -&gt; jekyll -&gt; middleman -&gt; jekyll。想來架系統的總時數應該超過寫文章的時間 XD</p>

<p>而這次用上了 <a target="_blank" href="https://www.gatsbyjs.org/">Gatsby</a> +
<a target="_blank" href="https://tailwindcss.com/">tailwindcss</a>，除了恢復一下 GraphQL
的手感之外，這次還挑戰了不套別人做的版型，自己把類似上一個部落格的 style 刻出來。想說來分享一下這些技術的感想：</p>
<h2 id="heading-gatsby">Gatsby</h2>
<p>雖然說是個 static site genertor，生成頁面的部份靠 React 來處理，開發時會啟動一個 nodejs server，將網站 meta-data 及檔案內容做成 GraphQL 的 endpoint，因此每個頁面都能簡單的拿到想要的資料。想要多拿欄位或是自訂欄位、變更取值的條件，甚至做 pagination 時，都是靠 GraphQL 段來處理的，因此改起來相當容易，graphiql 開起來就知道有什麼東西可以拿了，不必像 jekyll 那樣一直去翻 plugins 的文件。</p>
<p>Gatsby 本身的文件也蠻完整的，雖然沒有整理的非常好，看起來相對瑣碎一點，不過大部份想要的功能都找得到範例。像是 RSS、syntax hightligh 很快就能裝起來。 Mathjax 也沒有什麼難度，不過因為 mdx (React component in markdown) 的關係，語法有時候會壞掉，再看情況要不要換成 katex 好了。</p>
<div>
$\displaystyle
\mathcal P \mathcal A \mathcal 1:  1\ \in \mathbb N \\
\mathcal P \mathcal A \mathcal 2: \forall\ n\in\mathbb N\ [\ n'\in \mathbb N\ ] \\
\mathcal P \mathcal A \mathcal 3: \forall\ n\in \mathbb N \ [\ n' \neq 1\ ] \\
\mathcal P \mathcal A \mathcal 4: \forall\ m \in \mathbb N\ \forall\ n \in \mathbb N\;[\ m' = n'\Rightarrow m = n\ ] \\
\mathcal P \mathcal A \mathcal 5: (P(1) \land \forall\ k \in \mathbb N \; [\ P(k) \Rightarrow \ P(k')])\ \Rightarrow \forall\ n \in \mathbb N \; [\ P(n)\ ]
$
</div>

<p>如果想試試 React + GraphQL 的話，我覺得 Gatsby 是不錯的上手點。</p>
<h2 id="heading-tailwindcss">tailwindcss</h2>
<p>這個是被龍哥推坑的。認真玩了一下，發現 inline class style 跟 component style JS (React, Vue) 根本是天作之合。寫起來幾乎沒有在考慮樣式互相影響蓋來蓋去，應該要怎麼調整結構隸屬的問題。一般的專案由於打出來的 css 會很大包，需要用到 <a target="_blank" href="https://www.purgecss.com/">purgecss</a> 去清掉沒用到的樣式。而在 Gatsby 裡這段它在生成靜態頁面的時候就會幫你處理掉了。</p>
<p>之前看 tailwindcss 教學的時候發現作者用了 <a target="_blank" href="https://sizzy.co/">Sizzy</a>, 試用起來發現在調 RWD 的時候蠻好用的，不過軟體不太穩定，時不時會反應很慢，有些設定按鈕按下去一定會當機 XD 再觀察一陣子好了。</p>
<p><img src="./sizzy.jpg" alt /></p>
<h2 id="heading-migration">Migration</h2>
<p>由於 jekyll 也是用 markdown，所以寫個 python script 轉一下舊文章的檔案結構，手動清一下語法，花的時間比想像中少很多。</p>
<h2 id="heading-deploy">Deploy</h2>
<p>由於有人做好了 deploy 到 AWS s3 的 library，懶得重做就先搬到 AWS 了。希望不會多花太多錢 XD</p>
<hr />
<p>希望這樣會比較有動力寫文章。 XD</p>
]]></content:encoded></item><item><title><![CDATA[安裝 Elixir 環境]]></title><description><![CDATA[本文介紹幾種在電腦上安裝 Elixir / Erlang 環境的方法。
Mac
A. 使用 asdf (推薦)
asdf 是類 unix 作業系統上類似 rvm, rbenv 或 nvm 的語言版本管理套件。特別之處在於它可以安裝不同的 plugin 來管理多種不同的語言。
pre request

homebrew

git


Install

安裝 asdf 及 erlang 需要的元件

$ brew install \
  coreutils automake autoconf ope...]]></description><link>https://taian.su/2019-06-13-install-elixir-env</link><guid isPermaLink="true">https://taian.su/2019-06-13-install-elixir-env</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Thu, 13 Jun 2019 01:00:00 GMT</pubDate><content:encoded><![CDATA[<p>本文介紹幾種在電腦上安裝 Elixir / Erlang 環境的方法。</p>
<h2 id="heading-mac">Mac</h2>
<h3 id="heading-a-asdf">A. 使用 asdf (推薦)</h3>
<p><a target="_blank" href="https://github.com/asdf-vm/asdf">asdf</a> 是類 unix 作業系統上類似 rvm, rbenv 或 nvm 的語言版本管理套件。特別之處在於它可以安裝不同的 plugin 來管理<a target="_blank" href="https://github.com/asdf-vm/asdf-plugins">多種不同的語言</a>。</p>
<h3 id="heading-pre-request">pre request</h3>
<ul>
<li><p>homebrew</p>
</li>
<li><p>git</p>
</li>
</ul>
<h4 id="heading-install">Install</h4>
<ol>
<li>安裝 asdf 及 erlang 需要的元件</li>
</ol>
<pre><code class="lang-bash">$ brew install \
  coreutils automake autoconf openssl \
  libyaml readline libxslt libtool unixodbc \
  unzip curl wxmac asdf
</code></pre>
<ol>
<li>將 asdf init script 加到 zshrc 中，若你用的是 bash 或 fish 請參考<a target="_blank" href="https://asdf-vm.com/#/core-manage-asdf-vm?id=add-to-your-shell">官方說明</a>。<strong>這步之後需要重啟 shell</strong>。</li>
</ol>
<pre><code class="lang-bash">$ <span class="hljs-built_in">echo</span> -e <span class="hljs-string">'\n. /opt/homebrew/opt/asdf/libexec/asdf.sh'</span> &gt;&gt; ~/.zshrc
$ <span class="hljs-built_in">echo</span> -e <span class="hljs-string">'\n. /opt/homebrew/share/zsh/site-functions'</span> &gt;&gt; ~/.zshrc
</code></pre>
<ol>
<li>安裝 asdf 的 elixir 及 erlang plugin</li>
</ol>
<pre><code class="lang-bash">$ asdf plugin-add erlang
$ asdf plugin-add elixir
</code></pre>
<ol>
<li>用 asdf 安裝最新版的 Erlang。這一步一般來說需要很久，可以去聽個兩首歌再回來。</li>
</ol>
<pre><code class="lang-bash">asdf install erlang latest
asdf global erlang latest
</code></pre>
<ol>
<li>用 asdf 安裝最新版的 Elixir。由於 Elixir 是預編譯版本，所以可以選擇用符合自己 Erlang 版本編譯的版本。</li>
</ol>
<pre><code class="lang-bash">asdf install elixir latest
asdf global elixir latest
</code></pre>
<h4 id="heading-postgresql-nodejs">Postgresql 及 NodeJs</h4>
<p>如果想試試 phoenix，那麼需要安裝 postgresql 及 nodejs 5.5 以上的版本。這裡一樣使用 asdf 來安裝 nodejs，若你的系統中已存在其它 nodejs 版本，可以省略後面兩步。</p>
<pre><code class="lang-bash"><span class="hljs-comment"># 1. 安裝 postgresql</span>
$ brew install postgresql

<span class="hljs-comment"># 2. 安裝 asdf 的 nodejs plugin</span>
$ brew install gpg
$ asdf plugin-add nodejs


<span class="hljs-comment"># 3. 用 asdf 安裝 nodejs</span>
$ asdf install nodejs lts
</code></pre>
<h4 id="heading-5a6m5bel">完工</h4>
<p>試一下會不會動：</p>
<pre><code class="lang-bash">$ elixir -v
$ <span class="hljs-built_in">which</span> erl

<span class="hljs-comment">## 如果有裝 phoenix 的話</span>
$ mix phx.new --version
</code></pre>
<hr />
<h3 id="heading-b-homebrew">B. 使用 homebrew</h3>
<p>由於這個方法會跟著 homebrew upgrade 一起更新版本，所以比較適合下載來玩一下的情況。長時間的正式專案開發可能會遇到一些雷。</p>
<pre><code class="lang-plaintext">$ brew install erlang elixir
</code></pre>
<hr />
<h2 id="heading-c-docker">C. 使用 Docker</h2>
<ol>
<li>安裝 docker</li>
</ol>
<pre><code class="lang-bash">$ brew cask install docker
</code></pre>
<ol>
<li>拉官方 image。</li>
</ol>
<pre><code class="lang-bash">$ docker pull elixir
</code></pre>
<ol>
<li>跑起來試試看。按兩次 <code>Ctrl+C</code> 結束</li>
</ol>
<pre><code class="lang-bash">$ docker run -it --rm elixir iex
</code></pre>
<ol>
<li>執行本機上的 elixir 檔案</li>
</ol>
<pre><code class="lang-bash">$ docker run -it --rm -v $(<span class="hljs-built_in">pwd</span>):/tmp elixir elixir /tmp/my_elixir_file.ex
</code></pre>
<hr />
<h2 id="heading-ubuntudebian">Ubuntu/Debian</h2>
<h3 id="heading-a-asdf-1">A. 使用 asdf</h3>
<ol>
<li>安裝 asdf 及 erlang 需要的元件</li>
</ol>
<pre><code class="lang-bash">$ apt-get -y install build-essential autoconf m4 \
libncurses5-dev libwxgtk3.0-dev libgl1-mesa-dev libglu1-mesa-dev \
libpng-dev libssh-dev unixodbc-dev
</code></pre>
<p>接著參考 Mac 的 2 ~ 6 步</p>
<hr />
<h3 id="heading-centos-7">CentOS 7</h3>
<pre><code class="lang-bash">wget --no-verbose -P /tmp https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm

yum install -q -y /tmp/epel-release-latest-7.noarch.rpm

yum update -y -q

yum upgrade -y -q --enablerepo=epel

yum install -y -q wget curl unzip make git

yum install -y -q automake autoconf readline-devel ncurses-devel openssl-devel libyaml-devel libxslt-devel libffi-devel libtool unixODBC-devel

groupinstall -y <span class="hljs-string">'Development Tools'</span> <span class="hljs-string">'C Development Tools and Libraries'</span>

yum install -y -q wxGTK3-devel wxBase3 openssl-devel libxslt \
    java-1.8.0-openjdk-devel libiodbc unixODBC erlang-odbc

yum install -y -q install gpg perl perl-Digest-SHA
</code></pre>
<p>接著參考 Mac 的 2 ~ 6 步</p>
<hr />
<h2 id="heading-windows">Windows</h2>
<h3 id="heading-a-linux-sub-system">A. 使用 Linux Sub System (推薦)</h3>
<ol>
<li><p>參考<a target="_blank" href="https://docs.microsoft.com/zh-tw/windows/wsl/install-win10">微軟官方說明</a>，安裝 Linux 子系統。若不知道要用什麼的話，那就選 Ubuntu 吧。</p>
</li>
<li><p>啟動 Linux 子系統後，照著 Ubuntu/Debian 小節操作。</p>
</li>
</ol>
<h3 id="heading-b-scoop">B. 使用 scoop</h3>
<p>參考 <a target="_blank" href="https://scoop.sh">Scoop</a> 官網說明</p>
<ol>
<li><p>用系統管理者權限打開 powershell</p>
</li>
<li><p>貼上以下指令並按 [Enter] 執行</p>
</li>
</ol>
<pre><code class="lang-powershell"><span class="hljs-built_in">iwr</span> <span class="hljs-literal">-useb</span> get.scoop.sh | <span class="hljs-built_in">iex</span>
</code></pre>
<ol>
<li>安裝 elixir</li>
</ol>
<pre><code class="lang-powershell">scoop install elixir
</code></pre>
<ol>
<li>執行看看</li>
</ol>
<pre><code class="lang-powershell">iex.bat
</code></pre>
<h3 id="heading-c-chocolatey">C. 使用 chocolatey</h3>
<p>參考 <a target="_blank" href="https://chocolatey.org/install">chocolatey</a> 官網說明</p>
<ol>
<li><p>用系統管理者權限打開 powershell</p>
</li>
<li><p>貼上以下指令並按 [Enter] 執行 (從官網 copy 會比較方便)</p>
</li>
</ol>
<pre><code class="lang-powershell"><span class="hljs-built_in">Set-ExecutionPolicy</span> Bypass <span class="hljs-literal">-Scope</span> <span class="hljs-keyword">Process</span> <span class="hljs-literal">-Force</span>; [<span class="hljs-type">System.Net.ServicePointManager</span>]::SecurityProtocol = [<span class="hljs-type">System.Net.ServicePointManager</span>]::SecurityProtocol <span class="hljs-operator">-bor</span> <span class="hljs-number">3072</span>; <span class="hljs-built_in">iex</span> ((<span class="hljs-built_in">New-Object</span> System.Net.WebClient).DownloadString(<span class="hljs-string">'https://chocolatey.org/install.ps1'</span>))
</code></pre>
<ol>
<li>安裝 elixir</li>
</ol>
<pre><code class="lang-powershell">choco install elixir
</code></pre>
<ol>
<li>執行看看</li>
</ol>
<pre><code class="lang-powershell">iex.bat
</code></pre>
<h3 id="heading-d-docker">D. 使用 Docker</h3>
<p>同 Mac -&gt; C. 使用 Docker</p>
]]></content:encoded></item><item><title><![CDATA[Phoenix LiveView 概念篇]]></title><description><![CDATA[在 2018 九月 ElixirConf 的 ending keynote 中，Phoenix 的作者 Chris McCord 發表了正在開發中的新套件，Phoenix LiveView。而上週五 (3 月 15 日) 這個套件終於在 GitHub 上公開了。 本篇將介紹 Phoenix LiveView 的想解決的問題、基本概念，以及一些個人的想法。
簡單場景：Server side render
在介紹 Phoenix LiveView 之前，先來回頭看一個用 server side re...]]></description><link>https://taian.su/2019-03-25-phoenix-liveview</link><guid isPermaLink="true">https://taian.su/2019-03-25-phoenix-liveview</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Mon, 25 Mar 2019 03:10:00 GMT</pubDate><content:encoded><![CDATA[<p>在 2018 九月 <a target="_blank" href="https://elixirconf.com/">ElixirConf</a> 的 ending keynote 中，Phoenix 的作者 Chris McCord 發表了正在開發中的新套件，Phoenix LiveView。而上週五 (3 月 15 日) 這個套件終於在 GitHub 上<a target="_blank" href="https://github.com/phoenixframework/phoenix_live_view">公開</a>了。 本篇將介紹 Phoenix LiveView 的想解決的問題、基本概念，以及一些個人的想法。</p>
<h2 id="heading-server-side-render">簡單場景：Server side render</h2>
<p>在介紹 Phoenix LiveView 之前，先來回頭看一個用 server side render 寫出來的表單輸入場景：註冊帳號。首先使用者輸入 username 及 email，按下送出。發現註冊失敗，原來電話號碼是必填欄位。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688647299739/36b9ab43-e981-49e6-ab0a-3637f37e1f6c.png" alt class="image--center mx-auto" /></p>
<p><img src="./ssr1.png" alt /></p>
<p>接著亂填一個電話號碼，按下送出，錯誤訊息提示電話號碼格式不對。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688647315622/9d1e173d-109f-435c-9c8c-9af6963ccb63.png" alt class="image--center mx-auto" /></p>
<p><img src="./ssr2.png" alt /></p>
<p>把電話號碼改好後，按下送出，才發現這個 email 已經被註冊過了。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688647322523/770fdaa0-b003-4cd7-b361-11035b209dc7.png" alt class="image--center mx-auto" /></p>
<p><img src="./ssr3.png" alt /></p>
<p>換了一個 email 按下送出，這次才終於註冊成功。只有三個欄位的表單，使用者按下了四次送出鈕才完成。</p>
<h2 id="heading-javascript">下一步：用 JavaScript 改進</h2>
<p>我們想要的是當按下鍵盤按鍵時，就幫我們判斷格式是否正確，欄位是否有填完等等。為了改善這糟糕的互動體驗，主流的做法是引進 JavaScript 。通常會先以原生的 JavaScript ，或許再配上一點 jQuery 用 AJAX 來處理，接著依場景在前端實作將各種欄位的驗證及錯誤提示，當然後端的驗證還是要保留著。不然就會發生前沒多久某屈姓藥妝店的新聞了。</p>
<p>但隨著功能變多，沒有仔細規劃的話，我們的網頁就逐漸變成了一鍋「事件湯」。各個 listen events 間有錯綜複雜的觸發順序與依賴關係，一不小心就會讓該發生的事沒觸發到，或是不該發生的事件觸發了。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688648303954/ed334e9a-b801-4833-a119-d616847fbc0b.gif" alt class="image--center mx-auto" /></p>
<p>這時就會開始考慮使用 JavaScript 框架。但撇開漫長的工具棧選擇及組織社會性問題，各個頁面流程都得逐漸遷移到前端去。再來就發現頁面的 SEO 沒了，如果很在乎 SEO 的話，那就得在中間做一層 isomorphic layer，讓爬蟲也能爬到資料…</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688648360010/6b0fb3ec-eecc-4ee4-87ed-e05dc9e7d156.jpeg" alt class="image--center mx-auto" /></p>
<p><img src="./john.jpg" alt /></p>
<p>即使天時地利人和，總算把整個站改成了 Single Page Application 加上原本的後端的 Server。此時後端的 Server 已經變成一個純 API Server 了，那麼就會開始懷疑後端 Server 的實作方式是否符合目前架構的特性。舉例來說，為什麼要用 Rails 做純 API Server 呢？是不是改成 Sinatra ，甚至用 Golang 會比較好？</p>
<h1 id="heading-phoenix-liveview">Phoenix LiveView</h1>
<p>在許多情況下，我們只是想要一些些比較好的使用者互動而己。</p>
<p>可不可以沿用後端的頁面流程及驗證邏輯，卻又能即時的跟使用者互動呢？ Phoenix LiveView 就是在這個概念下產生的一種解法。</p>
<p>Chris McCord 在 announcement post 裡是這麼說的：</p>
<blockquote>
<p><em>Phoenix LiveView is an exciting new library which enables rich, real-time user experiences with server-rendered HTML. LiveView powered applications are stateful on the server with bidrectional communication via WebSockets, offering a vastly simplified programming model compared to JavaScript alternatives.</em></p>
</blockquote>
<p>Phoenix LiveView 讓你可以在 HTML tag 上用 <code>phx-</code> 屬性註明綁定的事件，但不是由前端進行處理，而是在事件觸發時，透過 websocket 將資料傳到後端，處理完成時後端主動將資料推至前端進行部份渲染。這麼一來，我們的網頁就有了保持狀態的能力，也就是上面引言中 “Stateful” 的意思。</p>
<p>在下圖的例子中，我們用 <code>phx-click="inc"</code>幫 + 這個按鈕綁上 <code>click</code> 事件。並在後端用 <code>handle_event/3</code> 處理接收到的 <code>inc</code> 事件資料。這樣一來每次按下這個按鈕，就會觸發事件，用 websocket 傳送資料到後端。處理完成後，一樣用 websocket 將資料傳回前端重新渲染 。由於 <code>handle_event/3</code> 是在 server 端處理的，所以這邊的程式可以直接呼叫原本的流程及驗證邏輯等既有程式。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688648406721/a2fe6c30-da63-42cf-ac9f-af9556b23899.png" alt class="image--center mx-auto" /></p>
<p><img src="./phx_binding.png" alt /></p>
<h2 id="heading-phoenix-channel">Phoenix Channel 效能</h2>
<p>José Valim 跟 Chris McCord 都說過他們開發這個語言/框架的最主要原因，就是平行化處理。因此 Phoenix 自專案開始就內建了 Channel 這個處理 WebSocket 協定的模組，在建立連線後，Server 端除了被動的接收從 Client 來的訊息之外，也可以主動推送資料到 Client 端。適用在聊天室等 Cllient 端需要知道 Server 端的連續狀態變化等場景。</p>
<p>得益於 Elixir / Erlang 優異的平行處理能力，Phoenix Channel 有在 55,000 使用者同時連線 websocket 的情況下，廣播訊息至 200 人的聊天室裡平均 0.24 秒的記錄。建構於其上的 Phoenix LiveView 甚至在官方 demo 裡放了一個 server side rendering 的動畫範例 <strong>rainbow</strong> ，純靠 server side 不斷的將更新的 div 推送到前端製造動畫效果。</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/egS4ySlTs_g">https://youtu.be/egS4ySlTs_g</a></div>
<p> </p>
<p>在我的電腦 (MacBook pro 15" 2015) 上，在不開 development tools 的情況下，60 fps 相當順暢，超過 85 fps 就會偶爾會出現卡頓感了。</p>
<h2 id="heading-6yyv6kqk6jmv55cg">錯誤處理</h2>
<p>除了平行處理的能力之外，Erlang 的另一個重要特性就是容錯能力 (fault tolerance)。當 phoenix channel 在 server 端發生執行期錯誤、或是接收到不存在的事件時，設計上會使得處理該 channel 的 process 陣亡，並由 supervisor tree 生成另一個新的 channel 與 client side 對接。</p>
<div class="embed-wrapper"><div class="embed-loading"><div class="loadingRow"></div><div class="loadingRow"></div></div><a class="embed-card" href="https://youtu.be/wz1zysiXjF4">https://youtu.be/wz1zysiXjF4</a></div>
<p> </p>
<p>從使用者的角度來看，當發生錯誤時，瀏覽器會短暫停頓(這時顯示的是 websocket 未連線的 fallback 畫面)，接著就回復初始的狀態。</p>
<h2 id="heading-6ygp5zci5ac05pmv">適合場景</h2>
<p>在 Elixir forum 的<a target="_blank" href="https://elixirforum.com/t/phoenix-liveview-is-now-live/20889/13">討論</a>裡，Chris McCord 指出 LiveView <strong>已知</strong>適合用在下列情況中：</p>
<ul>
<li><p>應用程式裡需要大量使用者互動的地方，如提示訊息、非同步工作狀態顯示、進度條、儀表板、附掛小工具等</p>
</li>
<li><p>表單互動。如驗證、會依不同選項變動的動態表單、設定精靈等</p>
</li>
<li><p>會需要即時知道 server 端狀態的東西</p>
</li>
<li><p>需要 server 參與的使用者互動，如搜尋、自動補完等</p>
</li>
</ul>
<p>在官方 Example 裡還放上了 LiveView 做出來的貪食蛇及 PACMAN 遊戲。在討論裡 Chris McCord 也說了這樣的話：「我們的計劃是先從小的地方開始，看看我們大家會用這個做出什麼東西來(，再決定之後的方向)。」</p>
<h2 id="heading-5ycl5lq65ooz5rov">個人想法</h2>
<p>Client side rendering 在這五六年蓬勃發展，也有它無可取代的應用場景。例如 Gmail、Netflix 等等。另外 server 端只做 API，而由不同樣態的客戶端如瀏覽器、手機 App 分別與之對接也是在規模變大時很常見的做法。</p>
<p><img src="./axis.png" alt /></p>
<p>但當 Phoenix LiveView 的出現帶來了另一種輕量級的可能性時，將應用程式改成 client side rendering 的決策壓力線將會向右推遲。而在與其它框架比較時，Phoenix 會在 websocket server 的候選清單中取得更為優勢的地位。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1688652469954/955df50c-e662-4951-b34c-e3c2262dd14b.png" alt class="image--center mx-auto" /></p>
<p>順帶一提目前已經有人把 <a target="_blank" href="https://github.com/montag/Live-Vue-Webcomponents">Phoenix LiveView 跟 Vue Component 搭在一起用</a> ，依這個思路與 React 或 Web Component 合併看來也完全可行，只是除了在遷移的過渡情況之外，還想不到能這樣能拿來幹麼就是了。</p>
<p>下一篇會導覽 Phoenix LiveView 的官方範例程式碼，敬請期待了。 Happy hacking!</p>
<h3 id="heading-references">References</h3>
<p><a target="_blank" href="https://www.youtube.com/watch?v=Z2DU0qLfPIY">ElixirConf 2018 Ending Keynote - Chris McCord</a></p>
<p><a target="_blank" href="https://github.com/phoenixframework/phoenix_live_view">Phoenix LiveView Repo</a></p>
<p><a target="_blank" href="https://github.com/chrismccord/phoenix_live_view_example">Phoenix LiveView Examples</a></p>
<p><a target="_blank" href="https://dockyard.com/blog/2018/12/12/phoenix-liveview-interactive-real-time-apps-no-need-to-write-javascript">Phoenix LiveView blogpost</a></p>
<p><a target="_blank" href="https://dockyard.com/blog/2016/08/09/phoenix-channels-vs-rails-action-cable">Phoenix Channel vs Rails ActionCable</a></p>
]]></content:encoded></item><item><title><![CDATA[Ruby 2.6 的新功能]]></title><description><![CDATA[Ruby 2.6 除了主打的 JIT 之外，還引進了一些有趣的新功能。其中有一些可以讓 Ruby 在函數式風格的寫法上更加自然流暢。想來稍微展示一下這些功能的用法。

1. Compose operator: Proc.>> 及 Proc.<<
雖然 Ruby 天生在某些用法上就採用了函數式風格(例如沒有 for 迴圈，而是用 each + block)，但由於高階函式接受的是 block 而非 lambda，lambda 本身也無法簡單組合起來。所以一直以來匿名函式在 Ruby 中除了拿來當參...]]></description><link>https://taian.su/2019-01-26-ruby-26</link><guid isPermaLink="true">https://taian.su/2019-01-26-ruby-26</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Sat, 26 Jan 2019 03:30:00 GMT</pubDate><content:encoded><![CDATA[<p>Ruby 2.6 除了主打的 JIT 之外，還引進了一些有趣的新功能。其中有一些可以讓 Ruby 在函數式風格的寫法上更加自然流暢。想來稍微展示一下這些功能的用法。</p>

<h2 id="heading-1-compose-operator-procandgtandgt-procandlt">1. Compose operator:<br /> <code>Proc.&gt;&gt;</code> 及 <code>Proc.&lt;&lt;</code></h2>
<p>雖然 Ruby 天生在某些用法上就採用了函數式風格(例如沒有 for 迴圈，而是用 each + block)，但由於高階函式接受的是 block 而非 lambda，lambda 本身也無法簡單組合起來。所以一直以來匿名函式在 Ruby 中除了拿來當參數傳遞之外，用法相當受限。</p>
<p>在正統的函數式編程中，用 function composition 的方式將多個小函式組合在一起是很基本的操作，舉個之前的例子，假設你想要這樣的連續調用：</p>
<pre><code class="lang-ruby"><span class="hljs-comment"># 注意，因為假設這些函數都是 lambda，所以要用 `.()` 調用</span>
request = generate_request.()
response = get_response.(request)
body = parse_body.(response)
html = render.(body)
</code></pre>
<p>其實除了 <code>html</code> 這個最終結果外，我們不需要中間的臨時變數，而可以改寫成這樣(然後被同事記恨)：</p>
<pre><code class="lang-ruby">html = render.(parse_body.(get_response.(generate_request.())))
</code></pre>
<p>Ruby 2.6 開始你可以用 <code>&lt;&lt;</code> (compose) 或是 <code>&gt;&gt;</code> (pipe) 來組合 Proc (或 lambda)。假設我們有兩個 lambda <code>f</code> 與 <code>g</code>，這兩個運算子的作用如下：</p>
<pre><code class="lang-ruby">(f &gt;&gt; g).(x)
<span class="hljs-comment"># 等同於</span>
g(f(x))


(f &lt;&lt; g).(x)
<span class="hljs-comment"># 等同於</span>
f(g(x))
</code></pre>
<p>我自己的記憶方式是把這兩個 operator 看成函式呼叫流程的箭頭。<code>f &gt;&gt; g</code> 就是先調用 <code>f</code> ，再將結果傳進 <code>g</code>。反之 <code>f &lt;&lt; g</code> 則是先調用 <code>g</code> 再傳給 <code>f</code>。</p>
<p>那麼之前的例子就可以改成下列兩者之一：</p>
<pre><code class="lang-ruby">get_html = generate_request &gt;&gt; get_response &gt;&gt; parse_body &gt;&gt; render
html = get_html.()

<span class="hljs-comment"># 或是</span>

get_html = render &lt;&lt; parse_body &lt;&lt; get_response &lt;&lt; generate_request
html = get_html.()
</code></pre>
<p>Ruby 2.6 的文件範例如下：</p>
<pre><code class="lang-ruby">f = proc {<span class="hljs-params">|x|</span> x * x}
g = proc {<span class="hljs-params">|x|</span> x + x}

(f &lt;&lt; g).call(<span class="hljs-number">2</span>) <span class="hljs-comment"># =&gt; 16</span>
(f &gt;&gt; g).call(<span class="hljs-number">2</span>) <span class="hljs-comment"># =&gt; 8</span>
</code></pre>
<p>再進階一點配合 Ruby 原本就有的 <code>Object#method</code> 及 <code>Method#curry</code>，想來可以組合出非常有意思的寫法。</p>
<h2 id="heading-2-enumerablefilter">2. Enumerable#filter</h2>
<p>函數式編程最著名的三個高階函式就屬 <code>map</code>、<code>reduce</code> 及 <code>filter</code> 了。但在 Ruby 中，<code>filter</code> 這個高階函式被改名為 <code>select</code>，這一版加上了 <code>filter</code> 的別名，跟其它語言的慣用法一致，再也不會等到測試爆掉才想起函式名稱不一樣了。</p>
<pre><code class="lang-ruby">[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>].filter {<span class="hljs-params">|i|</span> i % <span class="hljs-number">2</span> == <span class="hljs-number">0</span>} <span class="hljs-comment"># =&gt; [2, 4]</span>
</code></pre>
<h2 id="heading-3-endless-range">3. Endless range</h2>
<p>現在範圍運算子 <code>..</code> 可以不加結束的參數：</p>
<pre><code class="lang-ruby">[<span class="hljs-symbol">:a</span>, <span class="hljs-symbol">:b</span>, <span class="hljs-symbol">:c</span>, <span class="hljs-symbol">:d</span>][<span class="hljs-number">2</span>..] <span class="hljs-comment"># =&gt; [:b, :c, :d]</span>


(<span class="hljs-symbol">:b</span>..).lazy.zip(<span class="hljs-number">10</span>..).first(<span class="hljs-number">3</span>) <span class="hljs-comment"># =&gt; [[:b, 10], [:c, 11], [:d, 12]]</span>
</code></pre>
<h2 id="heading-4-arrayunion-and-arraydifference">4. Array#union and Array#difference</h2>
<p><code>Array#union</code> 是聯集，<code>Array#difference</code> 是差集。直接上範例：</p>
<pre><code class="lang-ruby">[<span class="hljs-number">1</span>].union([<span class="hljs-number">2</span>, <span class="hljs-number">3</span>], [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]) <span class="hljs-comment"># =&gt; [1, 2, 3, 4, 5]</span>


[<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>].difference([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">4</span>]) <span class="hljs-comment"># =&gt; [3, 3, 5]</span>
</code></pre>
<h2 id="heading-57wq6kqe">結語</h2>
<p>除了這些之外，<code>Proc.call</code> 調用快了大約 1.4 倍。另外還有 <code>Object#then</code>、<code>Hash#merge</code>、<code>Enumerable#to_h</code> 等等，就找機會試玩看看吧。Happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[Elixir 的並行機制：基礎部份]]></title><description><![CDATA[前陣子有幸可以亂入 Functional Thursday 介紹 Elixir 及 Erlang 。Q&A 時穆老師問了個「有沒有 lock 機制」的問題，覺得那時沒有回答好，想說寫篇文章來說明。也希望藉此機會，試著逐篇記錄一下我目前對 Erlang /Elixir 中並行機制的理解。

先說結論，Actor model 在應用層不需要鎖，因為不論讀寫，訊息是阻塞並依序處理的。
Actor model 概念
Erlang / Elixir 裡的並行機制是俗稱的 Actor model。在整個運行...]]></description><link>https://taian.su/2018-12-03-concurrent-in-elixir</link><guid isPermaLink="true">https://taian.su/2018-12-03-concurrent-in-elixir</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Mon, 03 Dec 2018 03:30:00 GMT</pubDate><content:encoded><![CDATA[<p>前陣子有幸可以亂入 <a target="_blank" href="https://www.facebook.com/events/261681544537519/">Functional Thursday 介紹 Elixir 及 Erlang</a> 。Q&amp;A 時穆老師問了個「有沒有 lock 機制」的問題，覺得那時沒有回答好，想說寫篇文章來說明。也希望藉此機會，試著逐篇記錄一下我目前對 Erlang /Elixir 中並行機制的理解。</p>

<p>先說結論，Actor model 在應用層不需要鎖，因為不論讀寫，訊息是<strong>阻塞並依序處理的</strong>。</p>
<h2 id="heading-actor-model">Actor model 概念</h2>
<p>Erlang / Elixir 裡的並行機制是俗稱的 Actor model。在整個運行的系統裡，每個獨立執行的單位稱之為 Actor。各個 Actor 間不與其它人共享記憶體，而是透過互相傳遞訊息來得知其它 Actor 所持有的資訊。就像是一個房間裡有很多人，每個人都各自做自己的事，如果有某個人想知道另一個人的知識，那就要主動開口問他並等待回覆。</p>
<p>在 Erlang / Elixir 裡，整個運行系統 (BEAM 虛擬機) 裡，可以產生多個 light-weight process。這個 process 並非作業系統的 process，而是啟動耗時 1~3 µs 的輕量虛擬機 process。如果你寫過物件導向的語言，可以把它想像成類似 object instance 的東西。</p>
<h2 id="heading-spawn1send2">前情提要：底層通訊機制 <code>spawn/1</code>、<code>send/2</code></h2>
<p>首先我們可以用 <code>spawn/1</code> 來生成一個 light-weight process (下稱 process)，傳入的參數是一個函數。<code>spawn/1</code> 的回傳值則是生成的 process 的 pid。而 process 間的溝通，則是用 <code>send/2</code> 帶上 <code>pid</code> 及要傳送的訊息。</p>
<p>例如我們可以讓新的 process 進行計算後，將結果傳給自己。由於 iex ( Elixir 的 repl ) 也是作為一個 process 啟動的，所以用 <code>self/0</code> 也可以拿到它的 pid，我們用它來試試訊息傳遞是怎麼一回事。</p>
<p>註：依 Elixir 慣例，<code>spawn/1</code> 代表名為 <code>spawn</code>， 接收<strong>一個參數</strong>的函式。其它依此類推。</p>
<pre><code class="lang-elixir">current_pid = <span class="hljs-keyword">self</span>() <span class="hljs-comment"># 拿到目前的 `pid`</span>

pid =
  spawn(<span class="hljs-keyword">fn</span> -&gt;
    result = <span class="hljs-number">1</span> + <span class="hljs-number">1</span> <span class="hljs-comment"># 做一些複雜的計算</span>
    send(current_pid, result)
  <span class="hljs-keyword">end</span>)

flush() <span class="hljs-comment"># 將收到的訊息全部沖出來看 (iex 限定函式)</span>
</code></pre>
<p>上例的圖示如下，我們在 iex 中，用 <code>self/0</code> 找到自己的 pid 為 0.101.0，用 <code>spawn/1</code> 生成一個新的 process，讓它在計算完成後，將結果用訊息送回 0.101.0。</p>
<p><img src="./spawn.png" alt /></p>
<p>到此為止是上次 meetup 時分享的內容。</p>
<h2 id="heading-receive1">用 <code>receive/1</code> 檢查信箱</h2>
<p>每個 actor (也就是 process) 都分別有一個不與其它人共用的信箱，依<strong>傳入時序</strong>存放未處理的訊息。讀取訊息時，則是依 FIFO 的順序取出。大概像是這樣：</p>
<p><img src="./mailbox.png" alt /></p>
<p>在 process 中要處理訊息時，會用 <code>receive/1</code> 來對收到的訊息進行 pattern matching。要注意的是一旦進入 <code>receive/1</code> 區塊，該 process 會<strong>阻塞</strong>並開始檢查信箱，直到比對到一筆符合的訊息，就調用該子句進行處理。</p>
<pre><code class="lang-elixir">current_pid = <span class="hljs-keyword">self</span>() <span class="hljs-comment"># 拿到目前 (iex) 的 `pid`</span>

pid =
  spawn(<span class="hljs-keyword">fn</span> -&gt;
    receive <span class="hljs-keyword">do</span>
      {caller, i} -&gt; send(caller, i + <span class="hljs-number">1</span>)
    <span class="hljs-keyword">end</span>
  <span class="hljs-keyword">end</span>)

<span class="hljs-comment">## 在 iex 裡操作生出來的 process</span>
send(pid, {current_pid, <span class="hljs-number">100</span>})
Process.alve?(pid) <span class="hljs-comment"># =&gt; process 死掉了 QoQ</span>
flush() <span class="hljs-comment"># =&gt; iex 收到 101 這條訊息</span>
</code></pre>
<p>在上面我們看到 process 處理完訊息之後就陣亡了。那是因為<strong>每個 <code>receive/1</code> 只處理一條訊息</strong>，就結束區塊阻塞，往下執行。而 <code>spawn/1</code> 在函式調用結束後，就會終止該 process 了。</p>
<h2 id="heading-process">持續活著的 process</h2>
<p>在上例中 receive/1 只執行(阻塞)一次，所以 process 在發送完訊息後生命週期就結束了。所以我們需要有個辦法讓它保持活著的狀態。我們先把參數用到的函式寫成具名函式，並將 <code>receive/1</code> 的區塊抽出來，這樣我們就可以遞迴的呼叫它。這麼一來這個 process 就能一直活著了。</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">PingPong</span></span> <span class="hljs-keyword">do</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span></span> <span class="hljs-keyword">do</span>
    spawn(&amp;loop/0) <span class="hljs-comment"># 生成 process 並回傳</span>
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">loop</span></span> <span class="hljs-keyword">do</span>
    receive <span class="hljs-keyword">do</span>
      {caller, <span class="hljs-symbol">:ping</span>} -&gt; send(caller, <span class="hljs-symbol">:pong</span>)
      {caller, <span class="hljs-symbol">:pong</span>} -&gt; send(caller, <span class="hljs-symbol">:blah</span>)
      <span class="hljs-symbol">:kabom</span> -&gt; exit(<span class="hljs-symbol">:normal</span>) <span class="hljs-comment"># 結束 process</span>
    <span class="hljs-keyword">end</span>

    loop() <span class="hljs-comment"># 用遞迴讓這個 process 活下去</span>
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment">## 在 iex 裡操作生出來的 process</span>
pid = PingPong.start
send(pid, {<span class="hljs-keyword">self</span>(), <span class="hljs-symbol">:ping</span>})
Process.alive?(pid) <span class="hljs-comment"># =&gt; true</span>

send(pid, {<span class="hljs-keyword">self</span>(), <span class="hljs-symbol">:pong</span>})
Process.alive?(pid) <span class="hljs-comment"># =&gt; true</span>

send(pid, <span class="hljs-symbol">:kabom</span>)
Process.alive?(pid) <span class="hljs-comment"># =&gt; false</span>

flush() <span class="hljs-comment"># 可以看到回傳的兩條訊息</span>
</code></pre>
<p>在上面的例子裡，當 <code>receive/1</code> 處理完一條訊息之後，我們就遞迴的呼叫 <code>loop/0</code> ，這樣就會啟動新一輪的 <code>receive/1</code> 來處理下一條訊息。我們可以看到在送出 <code>:kabom</code> 之前，該 process 一直是活著的。</p>
<h2 id="heading-process-1">帶著狀態的 process</h2>
<p>在 BEAM 虛擬機裡，process 有自己的 heap 及 stack，不與其它人共享，再加上 Erlang / Elixir 的值是 immutable 的，我們便可以讓 process 運行時記住一組資料，慣例上稱之為 process 的 <strong>state</strong>。需要讀取或是更新這個 state 的其它人，都只能用送訊息給這個 process 的方式讀寫。這個 process 即是這個狀態的 <strong>single source fo truth</strong>。聽說費波納契是函數式編程的 101, 那我們就來做一個 FibCounter：</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">FibCounter</span></span> <span class="hljs-keyword">do</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">start</span></span> <span class="hljs-keyword">do</span>
    init_state = [0, <span class="hljs-number">1</span>] <span class="hljs-comment"># 起始的 state</span>
    spawn(<span class="hljs-keyword">fn</span> -&gt; loop(init_state) <span class="hljs-keyword">end</span>)
  <span class="hljs-keyword">end</span>

  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">loop</span></span>([first, second] = state) <span class="hljs-keyword">do</span>
    next_state =
      receive <span class="hljs-keyword">do</span>
        <span class="hljs-symbol">:next</span> -&gt;
          [second, first + second] <span class="hljs-comment">## 更新狀態</span>
        {<span class="hljs-symbol">:get</span>, caller} -&gt;
          send(caller, first) <span class="hljs-comment">## 讀取狀態</span>
          state <span class="hljs-comment"># 保持一樣的 state</span>
        <span class="hljs-symbol">:reset</span> -&gt;
          [0, <span class="hljs-number">1</span>]
        <span class="hljs-symbol">:kabom</span> -&gt;
          exit(<span class="hljs-symbol">:normal</span>)
      <span class="hljs-keyword">end</span>

    loop(next_state)
  <span class="hljs-keyword">end</span>
<span class="hljs-keyword">end</span>

<span class="hljs-comment">## 在 iex 裡操作生出來的 process</span>
counter = FibCounter.start
send(counter, <span class="hljs-symbol">:next</span>)
send(counter, {<span class="hljs-symbol">:get</span>, <span class="hljs-keyword">self</span>()})
send(counter, <span class="hljs-symbol">:next</span>)
send(counter, <span class="hljs-symbol">:next</span>)
send(counter, <span class="hljs-symbol">:next</span>)
send(counter, <span class="hljs-symbol">:next</span>)
send(counter, {<span class="hljs-symbol">:get</span>, <span class="hljs-keyword">self</span>()})
send(counter, <span class="hljs-symbol">:reset</span>)
send(counter, {<span class="hljs-symbol">:get</span>, <span class="hljs-keyword">self</span>()})
flush <span class="hljs-comment"># =&gt; 拿到三條訊息，1, 5 跟 0</span>
send(counter, <span class="hljs-symbol">:kabom</span>)
</code></pre>
<p>應用程式裡我們可以到處傳遞 counter 這個 process，任何人都可以對它發送 <code>:next</code> 或是 <code>{:get, caller_pid}</code> 等訊息。</p>
<h2 id="heading-5qp5qyh5yq6jmv55cg5lia562g6kik5ogv">每次只處理一筆訊息</h2>
<p>當 process 進入 <code>receive/1</code> 區塊時，會取出信箱中第一筆(最早的)訊息，依序比對各個 pattern matching 子句。若成功比對就開始進行處理。若該訊息不符合任何 block，則擱置該訊息，並比對信箱中的下一筆訊息。若沒有比對到符合的訊息，則會阻塞到下一條訊息進來為止。因此不需要手動鎖定什麼東西，Actor model 就能保證發送訊息的人總是拿到最新的狀態 (對送訊時刻而言)。</p>
<h2 id="heading-5pc25l2u5byp6kq5bqm">搶佔式調度</h2>
<p>從微觀上來看，在接收到訊息之後，每個 process 會一直處在忙碌狀態中。那如果有 process 需要工作很長的時間，佔著 CPU 資源該怎麼辦呢？這時候就要從巨觀層面來看 Erlang 著名的<strong>搶佔式調度</strong>了。Erlang 在虛擬機上預設會為每個 CPU 核心配發一個 Scheduler，它會啟動一條 thread，並決定哪個 light-weight process 可以使用目前的 CPU 時間。scheduler 會為每個 process 計算函式調用的次數 (reduction) ，超過了使用次數，就會強制切換給另一個 process 工作，之後切換回來時再繼續未完成的部份。概略來說切換的頻率大約是數微秒一次。</p>
<p><img src="./otp_scheduler.png" alt /></p>
<p>這麼一來，就算系統中有 process 需要長時間的運算，也能保證其它的 process 依然可以取得 CPU 資源，將工作先執行完。</p>
<p><img src="./tasks.png" alt /></p>
<h2 id="heading-5z6d5zy6kik5ogv">垃圾訊息</h2>
<p>由於沒有比對到的訊息會被留在信箱裡，所以如果在信箱中堆積太多訊息時，會造成效能上的損耗。除了在環境參數或 process option 裡設定 <code>max_heap_size</code> 之外，你也可以在 <code>receive/1</code> 區塊中用子句來定期清理無效的訊息。</p>
<h2 id="heading-otp">OTP</h2>
<p>在實務上，Erlang / Elixir 較少直接使用 <code>spawn/0</code>或 <code>send/2</code> 來產生 process 及傳遞訊息。而是使用 Erlang 包裝好的 OTP (open telecom platform) 工具，例如 <code>GenServer</code> 、<code>Supervisor</code> 來建構系統。這部份就是下一篇的內容了 (如果有的話)。</p>
<h2 id="heading-6kix6agy">許願</h2>
<p>話說希望之後有機會可以再去 Functional Thursday 發表<strong>Haskell 相關</strong>的主題。 XD</p>
]]></content:encoded></item><item><title><![CDATA[Beyond Caps lock]]></title><description><![CDATA[應該不只一次跟別人提起：「如果這幾年用 mac 有學到些什麼的話，最重要的一件事肯定是把 Caps lock
改成 Ctrl」。是的，Caps lock 這麼重要的位置，居然放了這麼無用的鍵。把它換成 Ctrl 會讓你的生活品質大大提升。

但是最近跟其它人推廣這個小技巧時，有時會得到這樣的反應：「但是我都用 Caps lock 來切換輸入法」。顯然 macOS 有想要改進這個無用的鍵，讓它多發揮一些功能。macOS 目前的設計是，如果你快速的按下 Caps lock 放開，那麼就會觸發切換輸入...]]></description><link>https://taian.su/2018-01-21-beyond-caps-lock</link><guid isPermaLink="true">https://taian.su/2018-01-21-beyond-caps-lock</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Sat, 20 Jan 2018 19:10:00 GMT</pubDate><content:encoded><![CDATA[<p>應該不只一次跟別人提起：「如果這幾年用 mac 有學到些什麼的話，最重要的一件事肯定是<strong>把 Caps lock
改成 Ctrl</strong>」。是的，Caps lock 這麼重要的位置，居然放了這麼無用的鍵。把它換成 Ctrl 會讓你的生活品質大大提升。</p>

<p>但是最近跟其它人推廣這個小技巧時，有時會得到這樣的反應：「但是我都用 Caps lock 來切換輸入法」。顯然 macOS 有想要改進這個無用的鍵，讓它多發揮一些功能。macOS 目前的設計是，如果你快速的按下 Caps lock 放開，那麼就會觸發<strong>切換輸入法</strong>的行為。如果你按久一點，那就是原先的 Caps lock。</p>
<p>讓我們來從行為模式來思考一下幾個情況：</p>
<ol>
<li>Ctrl 是個綴詞鍵(或稱裝飾鍵)，當我們按下 Ctrl 時，必然是配合另一個鍵才會觸發我們想要的行為。</li>
<li>切換輸入法則是一個鍵就可以觸發的行為。</li>
</ol>
<p>所以如果我們可以做到這樣的事就完美了：</p>
<ol>
<li>當快速按下 Caps lock 並放開，觸發<strong>切換輸入法</strong></li>
<li>如果按著 Caps lock，並按下另一顆鍵，則視為 <strong>Ctrl + key</strong></li>
</ol>
<p>是的，這是辦得到的。但需要 <a target="_blank" href="https://pqrs.org/osx/karabiner/">Karabiner</a> 這個免費軟體，並稍加修改。</p>
<p><br /></p>
<ol>
<li><p>首先到 <a target="_blank" href="https://pqrs.org/osx/karabiner/index.html">https://pqrs.org/osx/karabiner/index.html</a>
下載並依指示安裝，執行後會看到底下的畫面(記得要到<strong>系統偏好設定 &gt; 安全性與隱私權</strong>打開相應的權限)：</p>
<p><img src="./bcp1.png" alt /></p>
</li>
<li><p>接著切換到 [Complex Modifications]，並按下左下角的 [Add rule]</p>
<p><img src="./bcp2.png" alt /></p>
</li>
<li><p>按下上方的 [import more rules from the Internet]</p>
<p><img src="./bcp3.png" alt /></p>
</li>
<li><p>這時瀏覽器會開啟，列入可以匯入的各種規則，找到 <strong>Modify Keys</strong> 區塊下的 <strong>Change caps_lock
key</strong>，按下右邊的 [Import]</p>
<p><img src="./bcp4.png" alt /></p>
</li>
<li><p>回到 Karabiner 視窗，就可以看到多出一些可用的規則。找到 <strong>Change caps_lock to control if pressed
with other keys, to escape if pressed alone.</strong>，按下右邊的 [Enable]。這個設定會在單獨按下時觸發
[ESC]，而跟其它鍵一起按的時候變成 [Ctrl + key]</p>
<p><img src="./bcp5.png" alt /></p>
</li>
<li><p>雖然上面的設定也很不錯，但是我還是想要切換輸入法。這就要動用到編輯器了，用你喜歡的編輯器打開
"~/.config/karabiner/karabiner.json"，找到我們匯入的規則區塊，也就是寫著 "description": "Change caps_lock to control..." 的那個 JSON object (花括號)。</p>
<p><img src="./bcp6.png" alt /></p>
</li>
<li><p>將底下的 "to_if_alone" 裡的 <strong>key_code</strong> 從 "esc" 改成 "caps_lock"，為了避免誤解，也順便將上方說明改成 "...to caps_lock if press alone."</p>
<p><img src="./bcp7.png" alt /></p>
</li>
<li><p>要切換輸入法，記得要在 macOS 的<strong>系統偏好設定 &gt; 鍵盤 &gt; 輸入方式</strong> ，將<strong>使用大寫鎖定鍵來切換...</strong> 核取方塊打勾</p>
<p><img src="./bcp8-compress.png" alt /></p>
</li>
</ol>
<p><em>Note:</em> 這個方式在切換到 macOS 內建的輸入法，如注音或是雙拼等都運作的很好。而我個人慣用的嘸蝦米，則是第一次要用 [Ctrl + Space] 切換到嘸蝦米之後，按下 [Ctrl] 可以輸入英文，再按一次回到嘸蝦米。不過右上角的輸入法則始終都會顯示嘸蝦米。</p>
<p><em>Note2:</em> 我的系統有裝 Better touch tool，本來想用它來改，但目前似乎不提供這種功能。但 BTT 跟 Karabiner 一起運用目前都蠻正常的。</p>
<p>Happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[List 操作小技巧]]></title><description><![CDATA[最近寫 Elixir 時，有個慣用的 functional 小手法，順手記錄一下。

1. 無差別包裝 List
當處理的對象可能是 nil， list，或是單個元素時，可以直接將它們包裝成單層的 list 進行後續操作。
Elixir 提供了 List.wrap 讓你直接將 nil 及 單個元素包裝成 list。對於原本就是 list 的對象則直接回傳：
# Elixir
List.wrap(nil)    # => []
List.wrap(1)      # => [1]
List.wra...]]></description><link>https://taian.su/2017-11-11-list-tricks</link><guid isPermaLink="true">https://taian.su/2017-11-11-list-tricks</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Fri, 10 Nov 2017 19:10:00 GMT</pubDate><content:encoded><![CDATA[<p>最近寫 Elixir 時，有個慣用的 functional 小手法，順手記錄一下。</p>

<h2 id="heading-1-list">1. 無差別包裝 List</h2>
<p>當處理的對象可能是 <code>nil</code>， <code>list</code>，或是單個元素時，可以直接將它們包裝成單層的 list 進行後續操作。</p>
<p>Elixir 提供了 <code>List.wrap</code> 讓你直接將 <code>nil</code> 及 單個元素包裝成 list。對於原本就是 list 的對象則直接回傳：</p>
<pre><code class="lang-elixir"><span class="hljs-comment"># Elixir</span>
List.wrap(<span class="hljs-keyword">nil</span>)    <span class="hljs-comment"># =&gt; []</span>
List.wrap(<span class="hljs-number">1</span>)      <span class="hljs-comment"># =&gt; [1]</span>
List.wrap([<span class="hljs-number">2</span>, <span class="hljs-number">3</span>]) <span class="hljs-comment"># =&gt; [2, 3]</span>
</code></pre>
<p>值得一提的是包裝 <code>nil</code> 會回傳空的 list，這對稍後要介紹的連續技起了重要的作用。</p>
<p>Ruby 則可以用 <code>Array()</code></p>
<pre><code class="lang-ruby"><span class="hljs-comment"># Ruby</span>
Array(<span class="hljs-literal">nil</span>)    <span class="hljs-comment"># =&gt; []</span>
Array(<span class="hljs-number">1</span>)      <span class="hljs-comment"># =&gt; [1]</span>
Array([<span class="hljs-number">2</span>, <span class="hljs-number">3</span>]) <span class="hljs-comment"># =&gt; [2, 3]</span>
</code></pre>
<p>在 JavaScript 裡就得要自己拼了，以 <code>Ramda</code> 為例：</p>
<pre><code class="lang-js"><span class="hljs-keyword">let</span> wrap = R.compose(R.filter(R.identity), R.unnest, R.of)

wrap(<span class="hljs-literal">null</span>)    <span class="hljs-comment">// =&gt; []</span>
wrap(<span class="hljs-number">1</span>)       <span class="hljs-comment">// =&gt; [1]</span>
wrap([<span class="hljs-number">2</span>, <span class="hljs-number">3</span>])  <span class="hljs-comment">// =&gt; [2, 3]</span>
</code></pre>
<p>這裡用 <code>R.unnest</code> 而非
<code>R.flatten</code>，是因為它不會把串列全部攤平至只剩一層。這個特性在你想要處理的「元素」本身就是一個陣列時會排上用場。</p>
<h2 id="heading-2-map">2. 攤開 <code>map</code> 的結果。</h2>
<p><code>flat_map</code> 可以將 map 的結果攤開到外層串列中。這個看範例會比較好懂：</p>
<pre><code class="lang-elixir">[<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
|&gt; Enum.flat_map(<span class="hljs-keyword">fn</span> x -&gt; [x, x] <span class="hljs-keyword">end</span>)

<span class="hljs-comment"># =&gt; [1, 1, 2, 2, 3, 3]</span>
</code></pre>
<p>flat_map 是函數式語言/函式庫基本的操作之一，應該都找得到。<code>Ramda</code> 裡叫 <code>R.chain</code>。</p>
<h2 id="heading-3">3. 連續技：優雅的消失</h2>
<p>結合上面兩個函式，先把含有 <code>nil</code> 的集合 <code>wrap</code> 成一個個的串列，再用 <code>flat_map</code> 或 <code>flatten</code> 攤開。這個時候就會發現 <code>nil</code> 在操作過程中直接消失了，不需要 <code>filter</code>，更不用 <code>if/else</code> 判斷。例如：</p>
<pre><code class="lang-elixir">class = %{
  <span class="hljs-symbol">teacher:</span> %{<span class="hljs-symbol">name:</span> <span class="hljs-string">"John"</span>, <span class="hljs-symbol">age:</span> <span class="hljs-number">40</span>},
  <span class="hljs-symbol">assistant:</span> <span class="hljs-keyword">nil</span>,
  <span class="hljs-symbol">students:</span> [%{<span class="hljs-symbol">name:</span> <span class="hljs-string">"Amber"</span>, <span class="hljs-symbol">age:</span> <span class="hljs-number">20</span>}, %{<span class="hljs-symbol">name:</span> <span class="hljs-string">"William"</span>, <span class="hljs-symbol">age:</span> <span class="hljs-number">22</span>}]
}

class
|&gt; Map.values
|&gt; Enum.flat_map(&amp;List.wrap/<span class="hljs-number">1</span>)

<span class="hljs-comment"># =&gt; [%{age: 20, name: "Amber"}, %{age: 22, name: "William"}, %{age: 40, name: "John"}]</span>
</code></pre>
<p>實際應用時，通常會直接將上層集合傳到 <code>flat_map</code> 裡，並將處理的函式拿出來另外宣告，這樣可以用 pattern matching 對上層結構做更細緻的處理。</p>
<p>Happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[Elixir 的 & 運算子]]></title><description><![CDATA[在跟朋友討論 Elixir 的過程中，發現常會需要解釋 & 運算子的用法，決定寫篇完整的來科普一下。

因為特殊符號很難 google 到正確的結果，& 在官方文件中的稱呼是 capture operator。它最主要的作用，就是補獲或是生成匿名函式。
Eta conversion
在 JavaScript 中，具名函式也是一級公民，可以直接傳遞。所以遇到在 lambda 中將接收到的參數原封不動傳給具名函式，並回傳其結果的情況下，可以直接傳遞具名函式。這在數學上叫 Eta conversion...]]></description><link>https://taian.su/2017-08-23-elixir-capture-operator</link><guid isPermaLink="true">https://taian.su/2017-08-23-elixir-capture-operator</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Wed, 23 Aug 2017 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p>在跟朋友討論 Elixir 的過程中，發現常會需要解釋 <code>&amp;</code> 運算子的用法，決定寫篇完整的來科普一下。</p>

<p>因為特殊符號很難 google 到正確的結果，<code>&amp;</code> 在官方文件中的稱呼是 capture operator。它最主要的作用，就是補獲或是生成匿名函式。</p>
<h2 id="heading-eta-conversion">Eta conversion</h2>
<p>在 JavaScript 中，具名函式也是一級公民，可以直接傳遞。所以遇到在 lambda 中將接收到的參數原封不動傳給具名函式，並回傳其結果的情況下，可以直接傳遞具名函式。這在數學上叫 Eta conversion。講起來很拗口，看範例就很直覺：</p>
<pre><code class="lang-js">[<span class="hljs-number">-1</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">3</span>].map(<span class="hljs-function"><span class="hljs-params">i</span> =&gt;</span> <span class="hljs-built_in">Math</span>.abs(i))

<span class="hljs-comment">// 等同於</span>

[<span class="hljs-number">-1</span>, <span class="hljs-number">-2</span>, <span class="hljs-number">3</span>].map(<span class="hljs-built_in">Math</span>.abs)
</code></pre>
<p>但在 Elixir 中，具名函式不加括號視同零參數的呼叫，因此我們需要有辦法將具名函式轉換成 lambda。這就是 <code>&amp;</code> 的第一個用法。在轉換其它 module 的函式 (正式名稱叫 <em>remote function</em>) 時，語法是 <code>&amp;Module.function/arity</code>，記得斜線後要帶上參數的個數。</p>
<pre><code class="lang-elixir">Enum.map([<span class="hljs-symbol">:a</span>, <span class="hljs-symbol">:b</span>, <span class="hljs-symbol">:c</span>], <span class="hljs-keyword">fn</span> a -&gt; Atom.to_string(a) <span class="hljs-keyword">end</span>)

<span class="hljs-comment"># 等同於</span>

Enum.map([<span class="hljs-symbol">:a</span>, <span class="hljs-symbol">:b</span>, <span class="hljs-symbol">:c</span>], &amp;Atom.to_string/<span class="hljs-number">1</span>)

<span class="hljs-comment">#=&gt; ["a", "b", "c"]</span>

<span class="hljs-comment"># 不能這樣寫</span>
Enum.map([<span class="hljs-symbol">:a</span>, <span class="hljs-symbol">:b</span>, <span class="hljs-symbol">:c</span>], Atom.to_string)

<span class="hljs-comment"># 因為上一句會被解析成這樣：</span>
Enum.map([<span class="hljs-symbol">:a</span>, <span class="hljs-symbol">:b</span>, <span class="hljs-symbol">:c</span>], Atom.to_string())
</code></pre>
<p>當然轉換 local fucntion 或 imported function 也沒問題，不加 Module 名稱就可以。</p>
<pre><code class="lang-elixir"><span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">double</span></span>(i), <span class="hljs-symbol">do:</span> i * <span class="hljs-number">2</span>

Enum.map([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], &amp;double/<span class="hljs-number">1</span>)

<span class="hljs-comment">#=&gt; [2, 4, 6]</span>
</code></pre>
<p>順帶一提，用 <code>&amp;</code> 補獲/生成的函式不一定要寫在高階函式中，也可以另外指派給變數。由於被轉換成 lambda 了，所以呼叫時要用 <code>.()</code>。</p>
<pre><code class="lang-elixir">f = &amp;Kernel.is_atom/<span class="hljs-number">1</span>

f.(<span class="hljs-symbol">:atom</span>) <span class="hljs-comment">#=&gt; true</span>
</code></pre>
<h2 id="heading-5yy5zcn5ye95byp">匿名函式</h2>
<p>Elixir/Erlang 裡，匿名函式的宣告比較冗長。因此遇到函式本體很短的情況下會覺得麻煩。</p>
<pre><code class="lang-elixir">Enum.map([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], <span class="hljs-keyword">fn</span> i -&gt; i * <span class="hljs-number">2</span> <span class="hljs-keyword">end</span>)
</code></pre>
<p>這種情況就是 <code>&amp;</code> 運算子派上用場的另一個地方，這也是最多人感到困惑的用法。</p>
<pre><code class="lang-elixir">Enum.map([<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>], &amp;(&amp;<span class="hljs-number">1</span> * <span class="hljs-number">2</span>))
<span class="hljs-comment">#=&gt; [2, 4, 6]</span>
</code></pre>
<p>換句話說，<code>fn i -&gt; i * 2 end</code> 跟 <code>&amp;(&amp;1 * 2)</code> 是一樣的意思。</p>
<h2 id="heading-list-tuple">生成 List 或 Tuple</h2>
<p>若用 <code>[]</code> 或 <code>{}</code> 代替圓括號，呼叫後的結果會分別是 <code>List</code> 及 <code>Tuple</code></p>
<pre><code class="lang-elixir">l = &amp;[&amp;<span class="hljs-number">1</span>, &amp;<span class="hljs-number">2</span>]
l.(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
<span class="hljs-comment">#=&gt; [1, 2]</span>

t = &amp;{&amp;<span class="hljs-number">1</span>, &amp;<span class="hljs-number">2</span>}
t.(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>)
<span class="hljs-comment">#=&gt; {1, 2}</span>
</code></pre>
<h2 id="heading-5pu05asa5yd5pw45yk5l255so5yik5rqw">更多參數及使用判準</h2>
<p><code>&amp;1</code> 是匿名函式接收到的第一個參數，多個參數也是可以的，就是 <code>&amp;2</code>、<code>&amp;3</code> 遞增下去。</p>
<pre><code class="lang-elixir"><span class="hljs-keyword">fn</span> = &amp;(&amp;<span class="hljs-number">1</span> + &amp;<span class="hljs-number">2</span> + &amp;<span class="hljs-number">3</span>)

fn.(<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>) <span class="hljs-comment">#=&gt; 6</span>
</code></pre>
<p>不過濫用 <code>&amp;()</code> 語法的話，程式很容易就會變得難讀。個人的判準是內部超過 10 個字元，或是有三個以上的運算子，就寧願用 <code>fn -&gt; end</code> 來宣告了。</p>
<p>那麼要做出 Haskell 的 <a target="_blank" href="https://www.haskell.org/hoogle/?hoogle=id">identity</a> 就簡單了： <code>&amp;(&amp;1)</code>。</p>
<pre><code class="lang-elixir">Enum.group_by([<span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>, <span class="hljs-string">"c"</span>, <span class="hljs-string">"a"</span>, <span class="hljs-string">"b"</span>], &amp;(&amp;<span class="hljs-number">1</span>))

<span class="hljs-comment"># =&gt; %{"a" =&gt; ["a", "a"], "b" =&gt; ["b", "b"], "c" =&gt; ["c"]}</span>
</code></pre>
<h2 id="heading-partial-application">Partial application</h2>
<p>綜合上面兩個語法，有種文件上沒寫清楚，很少人提，卻相當有用的用法。送了 PR 但還沒併進去。用 <code>&amp;1</code> 及 <code>&amp;Module.function</code> 作出 partially applied 的 remote function：</p>
<pre><code class="lang-elixir">take_five = &amp;Enum.take(&amp;<span class="hljs-number">1</span>, <span class="hljs-number">5</span>)
take_five.(<span class="hljs-number">1</span>..<span class="hljs-number">100</span>)

<span class="hljs-comment"># =&gt; [1, 2, 3, 4, 5]</span>
</code></pre>
<p>local function 也是一樣的:</p>
<pre><code class="lang-elixir">first_elem = &amp;elem(&amp;<span class="hljs-number">1</span>, 0)
first_elem.({<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>})
<span class="hljs-comment">#=&gt; 1</span>
</code></pre>
<p>大概就是這樣了。Happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[Pipe of JavaScript: _.chain()]]></title><description><![CDATA[Update: 後來發現這個解法有一些缺點。目前大多用 Ramda 的 pipe 或 compose 來處理。不然就等 tc39
上的 proposal 吧。


不知道從什麼時候開始，愈來愈喜歡用 functional 的寫法來處理問題。在看完 JavaScript
Allonge 之後更是一發不可收拾。上次的 Elixir 文章提到了愉快的 |> Pipe operator。一直想著怎麼 JavaScript 沒有類似的東西，但試過各種關鍵字就是找不到。

直到前陣子因工作需要，認真的翻了 ...]]></description><link>https://taian.su/2016-01-26-pipe-of-javascript</link><guid isPermaLink="true">https://taian.su/2016-01-26-pipe-of-javascript</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Tue, 26 Jan 2016 02:35:00 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>Update: 後來發現這個解法有一些缺點。目前大多用 Ramda 的 <code>pipe</code> 或 <code>compose</code> 來處理。不然就等 tc39
上的 proposal 吧。</p>
</blockquote>
<hr />
<p>不知道從什麼時候開始，愈來愈喜歡用 functional 的寫法來處理問題。在看完 <a target="_blank" href="https://leanpub.com/javascriptallongesix">JavaScript
Allonge</a> 之後更是一發不可收拾。上次的 <a target="_blank" href="/2014-07-26-a_sip_of_elixir/">Elixir 文章</a>提到了愉快的 <code>|&gt;</code> Pipe operator。一直想著怎麼 JavaScript 沒有類似的東西，但試過各種關鍵字就是找不到。</p>

<p>直到前陣子因<a class="post-section-overview" href="#1">工作需要</a>，認真的翻了 Lodash 文件，才發現真是踏破鐵鞋無覓處，那 function 就是接下來要介紹的 <code>_.chain()</code> 及 <code>_()</code>。找了一下中文世界似乎沒有什麼說明，寫個小心得看看是不是真的只有我 Lag 了 XD</p>
<p>先從問題開始，手邊有如下的資料結構：</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> poData =
  [
    { <span class="hljs-attr">poNumber</span>: <span class="hljs-string">'FA1234-1'</span>, <span class="hljs-attr">designName</span>: <span class="hljs-string">'A'</span>,,,, },
    { <span class="hljs-attr">poNumber</span>: <span class="hljs-string">'FA1234-5'</span>, <span class="hljs-attr">designName</span>: <span class="hljs-string">'B'</span>,,,, },
    { <span class="hljs-attr">poNumber</span>: <span class="hljs-string">'FB2234-1'</span>, <span class="hljs-attr">designName</span>: <span class="hljs-string">'C'</span>,,,, },
    { <span class="hljs-attr">poNumber</span>: <span class="hljs-string">'FC3141-1'</span>, <span class="hljs-attr">designName</span>: <span class="hljs-string">'D'</span>,,,, },
  ]
</code></pre>
<p>想要拿到不重複的 <code>poNumber</code> 的前半段。</p>
<pre><code class="lang-js">[<span class="hljs-string">'FA1234'</span>, <span class="hljs-string">'FB2234'</span>, <span class="hljs-string">'FC3141'</span>]
</code></pre>
<p>函數式的分解動作解法如下：</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> poNumbers     = _.map(poData, <span class="hljs-string">'poNumber'</span>)
<span class="hljs-keyword">const</span> poNumberParts = _.map(poNumbers, <span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num.split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">0</span>])
<span class="hljs-keyword">const</span> result        = _.unique(poNumberParts)

<span class="hljs-comment">// =&gt; ['FA1234', 'FB2234', 'FC3141']</span>
</code></pre>
<p>但其實我們不需要中間那些臨時變數，所以可以寫成這種 Wirte only 風格來累積仇恨值：</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> result = _.unique(_.map(_.map(poData, <span class="hljs-string">'poNumber'</span>), <span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num.split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">0</span>]))
</code></pre>
<p>縮排一下，看起來有點像 Lisp 了。但問題是執行順序是由內到外的，相當反直覺。</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> result = _.unique(
                  _.map(
                    _.map(poData, <span class="hljs-string">'poNumber'</span>),
                    <span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num.split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">0</span>]
                  )
                )
</code></pre>
<p>我們想要的，其實就是把函式執行的結果，當成呼叫下一個函數時的第一個參數。
而 Lodash 的 <code>_.chain()</code> 的功能正是如此：</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> result = _.chain(poData)
                .map(<span class="hljs-string">'poNumber'</span>)
                .map(<span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num.split(<span class="hljs-string">'-'</span>)[<span class="hljs-number">0</span>])
                .unique()
                .value()
</code></pre>
<p>由於 <code>_.chain()</code> 是 lazy evaluation，所以要在最後方加上 <code>.value()</code> 才會開始調用。否則只會回傳一個未調用的嵌套函式。 Lazy evaluation 的好處是上例中的兩個 <code>_.map</code> 及一個 <code>_.unique</code>，在實際執行時陣列只會遍歷一次，效能可能會比原先的寫法好一點。</p>
<p>另外 Lodash 還提供了 <code>_()</code>，如果在 chaining 過程中出現了 <code>_.reduce()</code>，<code>_.merge()</code>
等等會處理成單一結果，或是會回傳 primitive value 的函式調用，就會自動 unwrap。</p>
<pre><code class="lang-js"><span class="hljs-keyword">const</span> data = [
  {<span class="hljs-attr">name</span>: <span class="hljs-string">'A'</span>, <span class="hljs-attr">usdPrice</span>: <span class="hljs-number">10</span>},
  {<span class="hljs-attr">name</span>: <span class="hljs-string">'B'</span>, <span class="hljs-attr">usdPrice</span>: <span class="hljs-number">20</span>},
  {<span class="hljs-attr">name</span>: <span class="hljs-string">'C'</span>, <span class="hljs-attr">usdPrice</span>: <span class="hljs-number">30</span>},
]

<span class="hljs-keyword">const</span> twdTotal = _(data)
                .map(<span class="hljs-string">'usdPrice'</span>)
                .map(<span class="hljs-function"><span class="hljs-params">num</span> =&gt;</span> num * <span class="hljs-number">31</span>)
                .reduce(_.add)

 <span class="hljs-comment">// 呼叫了 _.reduce() ，所以不需要呼叫 _.value() 就會回傳數值</span>
 <span class="hljs-comment">// 這是個很假的範例不過你知道我意思。</span>
</code></pre>
<p>要注意雖然這個寫法看起來也是<em>一路點下去</em>，但是他的思路跟運作機制都與 jQuery 那種回傳 <code>self</code> 以繼續在同一個(變形過的) 物件上操作方法的 fluent style 是完全不同的。這種 chaining call 的運作方式是回傳一個用後方函式包裹前方函式的函式，讓你可以繼續包下去或調用。這概念及用法與 Rx.js 的 Observable 非常類似。</p>
<p>另外 underscore 也有 <code>_.chain()</code>，沒有仔細看但是印象中用法雷同。</p>
<hr />

<ul>
<li>即便是離開的資訊圈到南洋島國上做印刷，還是要處理傳產的 Excel 惡夢。反正沒有人要看 code，索性變本加厲的用上了 Rx.js。</li>
<li>呼叫函式 =&gt; call the function，函式調用 =&gt; function invocation。兩者同義，依行文流暢擇用。</li>
<li>最近繼續唸 Elixir/Erlang，OTP 好有趣啊。</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[復活節特價 Ruby 書敗家指南]]></title><description><![CDATA[@JuanitoFatas 今天分享了 紅寶石鐵道漫遊指南，
適逢本週感恩節特價，有人問起，就來快速列一些可以趁機入手的書。如果有閒的話，我再來補每本書的簡介。


Disclaimer:
這是敗家清單，想清楚再往下捲。
我不會由此推薦清單獲得任何實質上的利益。
絕大部份的書我都買了，但我整本看完的只有一部份。 XD


tl;dr: 就買 Confident Ruby 跟
Practical Object-Oriented Design in Ruby: An Agile
Primer
兩本。...]]></description><link>https://taian.su/2014-11-26-080000</link><guid isPermaLink="true">https://taian.su/2014-11-26-080000</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Wed, 26 Nov 2014 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p><a target="_blank" href="https://twitter.com/juanitofatas">@JuanitoFatas</a> 今天分享了 <a target="_blank" href="http://www.slideshare.net/katehuang0320/ss-42007998">紅寶石鐵道漫遊指南</a>，</p>
<p>適逢本週感恩節特價，有人問起，就來快速列一些可以趁機入手的書。如果有閒的話，我再來補每本書的簡介。</p>

<blockquote>
<p>Disclaimer:
這是敗家清單，想清楚再往下捲。
我不會由此推薦清單獲得任何實質上的利益。
絕大部份的書我都買了，但我整本看完的只有一部份。 XD</p>
</blockquote>
<hr />
<p>tl;dr: 就買 <a target="_blank" href="https://pragprog.com/book/agcr/confident-ruby">Confident Ruby</a> 跟
<a target="_blank" href="http://www.informit.com/store/practical-object-oriented-design-in-ruby-an-agile-primer-9780321721334">Practical Object-Oriented Design in Ruby: An Agile
Primer</a>
兩本。共約 37 USD。</p>
<hr />
<h1 id="heading-pragmatic-bookshelfhttpspragprogcom"><a target="_blank" href="https://pragprog.com/">Pragmatic Bookshelf</a></h1>
<blockquote>
<p>Discount Code: turkey2014
Discount: 50% for all ebooks
End date: Dec 1, 2014</p>
</blockquote>
<h3 id="heading-1-confident-rubyhttpspragprogcombookagcrconfident-ruby">1. <a target="_blank" href="https://pragprog.com/book/agcr/confident-ruby">Confident Ruby</a></h3>
<p>推薦指數: ☆☆☆☆☆ (必買)</p>
<p>這本書列出數十種如何寫出漂亮乾淨的 Ruby code 手法及準則。在我心中地位如同 <a target="_blank" href="http://www.books.com.tw/products/0010611737">Kent Beck 實作模式</a>的 Ruby 版。</p>
<h3 id="heading-2-exceptional-ruby-master-the-art-of-handling-failure-in-rubyhttpspragprogcombookagerexceptional-ruby">2. <a target="_blank" href="https://pragprog.com/book/ager/exceptional-ruby">Exceptional Ruby: Master the Art of Handling Failure in Ruby</a></h3>
<p>推薦指數: ☆☆☆☆</p>
<h3 id="heading-3-metaprogramming-ruby-2-program-like-the-ruby-proshttpspragprogcombookppmetr2metaprogramming-ruby-2">3. <a target="_blank" href="https://pragprog.com/book/ppmetr2/metaprogramming-ruby-2">Metaprogramming Ruby 2: Program Like the Ruby Pros</a></h3>
<p>推薦指數： ☆☆☆</p>
<p>我比較喜歡 Dave Thomas 這個 <a target="_blank" href="https://pragprog.com/screencasts/v-dtrubyom/the-ruby-object-model-and-metaprogramming">The Ruby Object Model and Metaprogramming</a> 影片，但是似乎沒有特價。</p>
<h3 id="heading-4-crafting-rails-4-applicationshttpspragprogcombookjvrails2crafting-rails-4-applications">4. <a target="_blank" href="https://pragprog.com/book/jvrails2/crafting-rails-4-applications">Crafting Rails 4 Applications</a></h3>
<p>推薦指數： ☆☆☆</p>
<p>Elixir 語言作者寫的好書，分析 Rails 內部如何運作。喜歡 meta-programming
的話，可以從這本裡看到許多實際上的用法。當然也比較進階一點。</p>
<h3 id="heading-5-build-awesome-command-line-applications-in-ruby-control-your-computer-simplify-your-lifehttpspragprogcombookdccarbuild-awesome-command-line-applications-in-ruby">5. <a target="_blank" href="https://pragprog.com/book/dccar/build-awesome-command-line-applications-in-ruby">Build Awesome Command-Line Applications in Ruby: Control Your Computer, Simplify Your Life</a></h3>
<p>推薦指數： ☆☆☆</p>
<p>試試 Ruby 除了 Web 還可以幹啥的好起點。</p>
<p>除此之外，<a target="_blank" href>Programming Ruby</a>, <a target="_blank" href>Agile Web Development with Rails 4</a>，<a target="_blank" href>The RSpec Book</a>
這種有一陣子的參考書就看個人想不想收了。</p>
<p>PS: 跟 Ruby 不那麼有關的，我想偷推一下 <a target="_blank" href="https://pragprog.com/book/elixir/programming-elixir">Programming Elixir</a> ♥♥♥♥♥</p>
<p>另加三本 Working with 系列基礎書：</p>
<ul>
<li><a target="_blank" href="https://pragprog.com/book/jsunix/working-with-unix-processes">Working with Unix processes</a></li>
<li><a target="_blank" href="https://pragprog.com/book/jsthreads/working-with-ruby-threads">Working with Ruby Threads</a></li>
<li><a target="_blank" href="https://pragprog.com/book/jstcp/working-with-tcp-sockets">Working with tcp sockets</a></li>
</ul>
<hr />
<h1 id="heading-informithttpwwwinformitcom"><a target="_blank" href="http://www.informit.com/">InformIT</a></h1>
<blockquote>
<p>Discount Code: BF2014
Discount: Buy 1 save 35%, 2 or more for 50%
End date: 沒說，應該就到本週五吧？</p>
</blockquote>
<h3 id="heading-1-practical-object-oriented-design-in-ruby-an-agile-primerhttpwwwinformitcomstorepractical-object-oriented-design-in-ruby-an-agile-primer-9780321721334">1. <a target="_blank" href="http://www.informit.com/store/practical-object-oriented-design-in-ruby-an-agile-primer-9780321721334">Practical Object-Oriented Design in Ruby: An Agile Primer</a></h3>
<p>推薦指數: ☆☆☆☆☆ (必買)</p>
<p>Object oriented 其實可以很輕巧，很靈活，很愉快。不是一大堆 UML 跟繁雜的大設計 ( 我不會說是什麼語言給我們這種印象 )。這本書說明各種設計的問題，並介紹 OO 裡的準則，並用簡單的 Ruby 實現。直指 Smalltalk 精神的 OO 觀念佳作。如果你只看一本教 OO 的書，那就選它吧。</p>
<h3 id="heading-2-eloquent-rubyhttpwwwinformitcomstoreeloquent-ruby-9780321584106">2. <a target="_blank" href="http://www.informit.com/store/eloquent-ruby-9780321584106">Eloquent Ruby</a></h3>
<p>推薦指數: ☆☆☆☆</p>
<h3 id="heading-3-refactoring-ruby-edition-ruby-editionhttpwwwinformitcomstorerefactoring-ruby-edition-ruby-edition-9780321984135">3. <a target="_blank" href="http://www.informit.com/store/refactoring-ruby-edition-ruby-edition-9780321984135">Refactoring: Ruby Edition: Ruby Edition</a></h3>
<p>推薦指數: ☆☆☆☆</p>
<p>如果你有 Java 版的話，那就不用多買。如果你看得懂 Java，那中文版比較便宜。 XD</p>
<h3 id="heading-4-effective-ruby-48-specific-ways-to-write-better-rubyhttpwwwinformitcomstoreeffective-ruby-48-specific-ways-to-write-better-ruby-9780133846973">4. <a target="_blank" href="http://www.informit.com/store/effective-ruby-48-specific-ways-to-write-better-ruby-9780133846973">Effective Ruby: 48 Specific Ways to Write Better Ruby</a></h3>
<p>這本我買了還沒翻開過…</p>
<p><a target="_blank" href="http://www.informit.com/store/design-patterns-in-ruby-9780321490452">Design Patterns in Ruby</a>，<a target="_blank" href="http://www.informit.com/store/rails-4-way-9780321944276">Rails 4 Way</a> 就看個人需求了。</p>
<hr />
<h1 id="heading-no-starch-press"><a target="_blank" href>no starch press</a></h1>
<blockquote>
<p>Discount Code: GRAVYBOAT
Discount: 50% for all ebooks
End date: Nov 26, 2014</p>
</blockquote>
<h3 id="heading-1-ruby-under-a-microsopehttpwwwnostarchcomrum">1. <a target="_blank" href="http://www.nostarch.com/rum">Ruby Under a Microsope</a></h3>
<p>推薦指數: ☆☆☆☆</p>
<p>這本在講 Ruby 內部的運作原理，算是理論書。我自己是蠻喜歡的啦…</p>
<h3 id="heading-2-rails-crash-coursehttpwwwnostarchcomrailscrashcourse">2. <a target="_blank" href="http://www.nostarch.com/railscrashcourse">Rails Crash Course</a></h3>
<p>@JuanitoFatas 簡報裡有列，這本我沒看過也沒有買…</p>
<p>Warning: 聽說 <a target="_blank" href="http://www.nostarch.com/ruby">Book of Ruby</a> 這本蠻雷的…</p>
]]></content:encoded></item><item><title><![CDATA[淺嚐 Elixir]]></title><description><![CDATA[來聊一下最近在唸的新玩具： Elixir。
發音是：「ㄦ利ㄎ洗爾」

Why Elixir
是說去年底 Peepcode 還活著的時候有出過一集 Elixir 的教學。我一直蠻仰慕這個寫出這本厲害的 Craft Rails Applications 的作者 José Valim ，但是這影片一直在 stack 的最底端沒機會去看。( 話說 José 是巴西人，回頭去看影片，一直會聽到小舌音的 "ㄟ赫爾"，要仔細聽前後文才發現是 "error"。)
一直到上次 Dave Thomas 路過台灣被 ...]]></description><link>https://taian.su/2014-07-26-a-sip-of-elixir</link><guid isPermaLink="true">https://taian.su/2014-07-26-a-sip-of-elixir</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Sat, 26 Jul 2014 00:00:00 GMT</pubDate><content:encoded><![CDATA[<p>來聊一下最近在唸的新玩具： <a target="_blank" href="http://elixir-lang.org">Elixir</a>。
發音是：「ㄦ利ㄎ洗爾」</p>

<h1 id="heading-why-elixir">Why Elixir</h1>
<p>是說去年底 Peepcode 還活著的時候有出過一集 Elixir 的教學。我一直蠻仰慕這個寫出這本厲害的 <a target="_blank" href="http://pragprog.com/book/jvrails2/crafting-rails-applications">Craft Rails Applications</a> 的作者 <a target="_blank" href="https://twitter.com/josevalim">José Valim</a> ，但是這影片一直在 stack 的最底端沒機會去看。( 話說 José 是巴西人，回頭去看影片，一直會聽到小舌音的 "ㄟ赫爾"，要仔細聽前後文才發現是 "error"。)</p>
<p>一直到上次 <a target="_blank" href="https://twitter.com/pragdave">Dave Thomas</a> 路過台灣被 Ruby Taiwan 社群拉來<a target="_blank" href="http://rubytaiwan.kktix.cc/events/dave-drinkup">吃熱炒</a>，席間聊到他寫的新書 <a target="_blank" href="http://pragprog.com/book/elixir/programming-elixir">Programming Elixir</a> 。他說電腦跟手機核心愈來愈多，分散式運算是肯定是未來五年最重要的課題之一，也提到最後出線的也許不是 Elixir ，但是出頭的那個語言必然會有相似的概念 ( 看看 go 那個精美的 goroutine ) 。加上他總是說一年要學一門讓你重新思考的新語言，講的這麼有趣，一頓飯吃完腦也被順利的洗過一輪了。</p>
<h1 id="heading-what-is-elixir">What is Elixir</h1>
<p>2012 才發表的 Elixir 是建在 Erlang Virtual Machine (BEAM) 上的函數式語言。繼承 Erlang 優秀的分散式運算模型 Actor model ，「目標是在 Erlang 生態系裡帶進高生產力及高擴展性的開發過程」。簡單來說就是像 Ruby 的漂亮語法，更一致的操作跟 meta-programming 能力。</p>
<p>Elixir 這個字是萬靈藥的意思。Dave 的新書裡還開了這樣一個玩笑："Of course, I'm not saying that Elixir is a magic potion (well, technically it is, but you know what I mean)."</p>
<blockquote>
<p>Disclaimer: Elixir 當下版本為 0.14.3。最近幾乎每個月都會有更新。雖然已有公司用在正式環境上，但幾乎都是原來就使用 Erlang 的公司才敢這麼做。另外我書也還沒整本看完。 XD</p>
</blockquote>
<hr />
<h1 id="heading-5oir5zac5q2h55qe6yoo5lu9">我喜歡的部份</h1>
<h2 id="heading-0-script-and-compiled">0. Script and compiled</h2>
<p>  Elixir 有兩種副檔名：<code>ex</code> 及 <code>exs</code>。執行 <code>exs</code> 副檔名時，預設會直譯並執行。若是 <code>ex</code> 副檔名，則會編譯成 BEAM binary 後執行。想要手動編譯 <code>exs</code> 檔案也是可以的。</p>
<h2 id="heading-1-pattern-matching">1. 樣式比對 (Pattern matching)</h2>
<p>Elixir ( 及 Erlang ) 的等號並不是單純的指派，而是樣式比對。當我們在數學上說 <code>y = x + 1</code> 時，並不是說把 <code>y</code> 指派成 <code>x + 1</code>。而是說當 <code>x</code> 為某值時，<code>y</code> 會依規則 ( 這裡指的是 + 1 ) 比對成另外一個值。</p>
<p>在 Ruby 中，當你寫</p>
<pre><code class="lang-ruby">a, a, b = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>] <span class="hljs-comment"># =&gt; a 會是 2</span>
</code></pre>
<p>因為第二次指派覆蓋了第一次指派。</p>
<p>而在 Elixir 中，則是這樣：</p>
<pre><code class="lang-elixir">[a, a, b] = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>]
<span class="hljs-comment"># =&gt; ** (MatchError) no match of right hand side value: [1, 2, 3]</span>

[a, a, b] = [<span class="hljs-number">1</span>, <span class="hljs-number">1</span>, <span class="hljs-number">3</span>]
<span class="hljs-comment"># =&gt; 因為能成功比對，a 會是 1，b 則是 3</span>
</code></pre>
<p>樣式比對在 Elixir 裡用法相當巧妙，例如：</p>
<pre><code class="lang-elixir">[ head | tail ] = [<span class="hljs-number">1</span>, <span class="hljs-number">2</span>, <span class="hljs-number">3</span>, <span class="hljs-number">4</span>, <span class="hljs-number">5</span>]
<span class="hljs-comment"># =&gt;  head 是 1, tail 是 [2, 3, 4, 5]</span>
</code></pre>
<p>以及函式呼叫：</p>
<pre><code class="lang-elixir">parse_response = <span class="hljs-keyword">fn</span>
  {<span class="hljs-symbol">:ok</span>, value}  -&gt; render(value)
  {<span class="hljs-symbol">:err</span>, msg} -&gt; show_error(msg)
<span class="hljs-keyword">end</span>

parse_response.(response)
</code></pre>
<p>會依 <code>response</code> 是 <code>{:ok, something}</code> 或是 <code>{:err, something}</code> 決定執行的方法區塊。</p>
<h2 id="heading-2-list-and-recursive">2. List and Recursive</h2>
<p>有了上面的樣式比對，就可以寫出非常漂亮的遞迴函式：</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">Factorial</span></span> <span class="hljs-keyword">do</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calc</span></span>(0), <span class="hljs-symbol">do:</span> <span class="hljs-number">1</span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calc</span></span>(val), <span class="hljs-symbol">do:</span> val * calc(val - <span class="hljs-number">1</span>)
<span class="hljs-keyword">end</span>
</code></pre>
<p>以及 list 處理函式：</p>
<pre><code class="lang-elixir"><span class="hljs-class"><span class="hljs-keyword">defmodule</span> <span class="hljs-title">Sum</span></span>
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calc</span></span>([]), <span class="hljs-symbol">do:</span> 0
  <span class="hljs-function"><span class="hljs-keyword">def</span> <span class="hljs-title">calc</span></span>([ head | tail]), <span class="hljs-symbol">do:</span> head + calc(tail)
<span class="hljs-keyword">end</span>
</code></pre>
<h2 id="heading-3-pipe-operator">3. Pipe operator</h2>
<p>我們常常看到這種程式：</p>
<pre><code class="lang-elixir">request = generate_request
response = get_response(request)
body = parse_body(response, <span class="hljs-symbol">:html</span>)
html = render(body)
</code></pre>
<p>因為若想省去中間那些暫時的變數，就要寫成這樣：</p>
<pre><code class="lang-ruby">html = render(parse_body(get_response(generate_request), <span class="hljs-symbol">:html</span>))
</code></pre>
<p>這看起來更醜，你得要從裡面讀到外面，而且還常常找不到開始讀的點。</p>
<p>Pipe operator <code>|&gt;</code> 可以讓你把回傳值當成下一個函式呼叫的第一個參數。所以上面的例子會寫成：</p>
<pre><code class="lang-elixir">html = generate_request
       |&gt; get_response
       |&gt; parse_body(<span class="hljs-symbol">:html</span>)
       |&gt; render
</code></pre>
<p>當看到上面的寫法之後，我好像看懂了底下這句話：</p>
<blockquote>
<p>Functional programming is like a jounery of data transforming.</p>
</blockquote>
<hr />
<h2 id="heading-56i5pog77ym5pyj5qmf5pyd5yan5l6g5ar77ya">稿擠，有機會再來寫：</h2>
<ul>
<li>The function capture notation</li>
<li>Spawn a process</li>
<li>pmap</li>
<li>Meta-programming with marco</li>
<li>Mix and Doctest</li>
</ul>
<p><br /></p>
<hr />
<h2 id="heading-what-i-feel-until-now">What I feel until now:</h2>
<p>之前有短暫的摸過 Clojure，也唸了兩章 SICP。不過這幾個週學 Elixir，時不時有種頓悟的感覺。好像又多了解 Functional programming 一點點。更重要的是，這語言到目前為止，讓我獲得非常多的樂趣。</p>
<p>Happy hacking!</p>
]]></content:encoded></item><item><title><![CDATA[Listen Jazz: Improvisation]]></title><description><![CDATA[話說幾年前有個部落格叫「爵士道 (Jazztao)」，雖然生性散漫的只寫了三、五篇文章。最後還因為閃神不小心砍掉整個 Google 帳號而從此沉沒。但有時想起還是會好奇著：「要是那時繼續寫下去，會是怎麼樣子呢?」

在那個沉沒的部落格裡，我最懷念的一篇是叫：「二十分鐘，弄懂爵士樂在搞什麼鬼 - 談爵士樂的進行模式與即興。」想說就試著從這裡再接關看看吧。
那篇文章是這樣開始的： 先想像一個賽車跑道。電視上看過的也好，遊戲裡玩過的也好。就是那種有直線，也有很多轉彎的長長柏油路賽道。照慣例也總會有個黑...]]></description><link>https://taian.su/2014-05-29-listen-jazz-improvisation</link><guid isPermaLink="true">https://taian.su/2014-05-29-listen-jazz-improvisation</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Thu, 29 May 2014 00:00:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271186631/bbf40e35-a573-4a4c-b1ad-33a9ebf9cf1f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<p>話說幾年前有個部落格叫「爵士道 (Jazztao)」，雖然生性散漫的只寫了三、五篇文章。最後還因為閃神不小心砍掉整個 Google 帳號而從此沉沒。但有時想起還是會好奇著：「要是那時繼續寫下去，會是怎麼樣子呢?」</p>

<p>在那個沉沒的部落格裡，我最懷念的一篇是叫：「二十分鐘，弄懂爵士樂在搞什麼鬼 - 談爵士樂的進行模式與即興。」想說就試著從這裡再接關看看吧。</p>
<p>那篇文章是這樣開始的： 先想像一個賽車跑道。電視上看過的也好，遊戲裡玩過的也好。就是那種有直線，也有很多轉彎的長長柏油路賽道。照慣例也總會有個黑白方格交錯看板的起點/終點。</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271186631/bbf40e35-a573-4a4c-b1ad-33a9ebf9cf1f.jpeg" alt /></p>
<hr />
<p>而對爵士樂手來說，這個跑道的<strong>一圈</strong>，長得像是這個樣子：</p>
<p><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271189141/a42b3d2d-1e61-4d06-9a49-f8992b5ffa0b.jpeg" alt /></p>
<p>這張樂譜寫上了主旋律，以及每個小節的和弦。範例中這首 Autumn Leaves 應該是許多人耳熟能詳的曲子。我在 Youtube 上找了個很有名的版本放在底下。而在你開始播放之前，要提醒你兩件事情。第一是底下的文章會有很多 <code>分:秒</code> 的時間標記。看見時記得回頭瞄一下播放器，留神聽聽看那些時間點前後的聲音有什麼不同。</p>
<iframe width="560" height="315" src="https://www.youtube.com/embed/tguu4m38U78"></iframe>


<hr />
<p>剛開始是前奏，鋼琴、Double Bass 跟鼓。 Saxphone 一句一句，像是賽前的暖身。小號加了一些刺刺的聲音。<code>00:54</code>，開始從起跑線，也就是樂譜的第一小節出發了，小號奏起你熟悉的旋律。到 <code>02:01</code>  時，樂譜已經跑到了盡頭。但這只是第一圈而己，對爵士樂來說，故事才正要開始精采。</p>
<p>跟賽車一樣，鼓、Double Bass 跟鋼琴回到樂譜的起點，將相同的和弦進行再重覆一次 ( 上方的 <code>Am7</code>、<code>D9</code>是所謂的和弦。和弦的組合順序稱之為 "和弦進行" ) 。而樂手中，會有一個人跳出來開始「即興」。</p>
<p>所謂的「即興」，就是在這些和弦進行裡，當下想出另一條可行的旋律線。樂理上來想例如 「Am7 - D9 - GMaj7 可以處理成 II-V-I」，雖然原理上是這樣，樂手計算的速度得要比說這句話的時間短上許多。大家也會試著探索更刺激，更有趣的聲音可能性。故意繞到和弦邊邊，弄出很不協調的聲音再接回來。大概就是「賽車時壓上山路的水溝蓋超車」那麼一回事吧。「怎麼會想出這樣的聲音呢?」在爵士樂裡，是再好不過的稱讚了。</p>
<p>一路開到<code>03:11</code>，Saxphone 手 Cannonball Adderley 還沒玩過癮，繼續再跑一圈。旋律又跟上一圈完全不同。一開始是高低音大跳躍的句子，中間用了許多切分音玩不一樣的節奏。最後再來很多快速的長短句。 </p>
<p>曲子走到 <code>04:21</code>，小號手 Miles Davis 接手。不像 Cannoball 那種快速的句型，他的語法比較不慍不火，卻總是能在棒的要命的時機丟出難度很高的句子。<code>05:30</code>又是第二圈，長音加上許多的短句。起頭聽起來很像原來的旋律，繞個彎卻又是另一番風景。</p>
<p>鋼琴手 Sam Jones 在 <code>06:40</code>拿下接力棒，開始這首曲子的第六圈。在很像原曲句子的變奏裡，把腳偷偷踩出線，又漂亮的踩回來。</p>
<p><code>07:46</code>，結束了各自的炫耀時間，大家回到主旋律再跑上最後一圈。<code>08:30</code>鋼琴手在半圈的地方意猶未盡般獨奏了一小段。<code>08:57</code>曲子跑完，又用前奏的和弦多跑了幾個小節的尾奏才結束這首曲子。</p>
<p>那麼故事就是這樣了。除了早期 Big band 時代之外，四零年代中期的 Bebop 樂手們開始確立了這種「樂曲只是載具、即興才是本體」的競技，這個格式便成為爵士樂的慣例。要分辨「爵士樂」或是「具有爵士風格的流行樂」，看看是不是在兩個「主旋律」間，夾了「整數倍長度的即興」，就是一個很好上手的判斷方式。</p>
<p>試著去 Youtube 上找找看其它的 Autumn Leaves 版本。或是看看影片那張封面圖，找找那些樂手的名字。在那些名字或是曲名背後，有著無數有趣的聲音等著你去發現。</p>
<p>剛剛在放音樂之前，說過要提醒兩件事。那麼第二件事情，就是這張叫 “SOMETHIN' ELSE” 專輯的每一首都很好聽。記得去買。</p>
<hr />
<p>後記： 這篇文章在我的草稿夾裡躺了一年。外頭下著大雨，想到就信手改一改發了。如果有想到什麼好的切入點，就再看看有什麼可以寫的吧。</p>
<p>廣告： 我的朋友華勁，六月底會在台中開課講 <strong><a target="_blank" href="http://groovement-music.com/school/curriculum/content.php?cid=36&amp;id=297">紐約爵士現在在搞什麼</a></strong>。</p>
<p>廣告 Part II: 明諺新專輯的巡迴表演，從<a target="_blank" href="https://www.facebook.com/events/371172876354519/">明天晚上台北 Sappho</a> 開始。</p>
]]></content:encoded></item><item><title><![CDATA[Meta and meta-programming]]></title><description><![CDATA[「我的語言的界限，就是我的世界的界限。」  -- Ludwig Wittgenstein


最近在讀 meta-programming 的東西，翻到一些網路上的爭論。想到幾年前，一個通曉多國語言的日本朋友問我：「meta-programming 裡的 meta 這個字在台灣怎麼翻?」，那時我是麼回的：「有時候翻中介，有時候翻後設，有時就乾脆不翻了。」
我認為 meta 的翻譯，就是爭論的來源。
無論是把 "meta-programming" 翻成「中介編程」，還是把 "meta-fiction...]]></description><link>https://taian.su/2013-06-29-meta-and-meta-programming</link><guid isPermaLink="true">https://taian.su/2013-06-29-meta-and-meta-programming</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Fri, 28 Jun 2013 17:49:00 GMT</pubDate><content:encoded><![CDATA[<blockquote>
<p>「我的語言的界限，就是我的世界的界限。」  -- Ludwig Wittgenstein</p>
</blockquote>

<p>最近在讀 meta-programming 的東西，翻到一些網路上的爭論。想到幾年前，一個通曉多國語言的日本朋友問我：「meta-programming 裡的 meta 這個字在台灣怎麼翻?」，那時我是麼回的：「有時候翻中介，有時候翻後設，有時就乾脆不翻了。」</p>
<p>我認為 meta 的翻譯，就是爭論的來源。</p>
<p>無論是把 "meta-programming" 翻成「中介編程」，還是把 "meta-fiction" 翻成「後設小說」，在字面上都只是讓我更困惑而己。meta 這個字其實很有趣，基本上就是「關於 X 的 X」。舉幾個例子:</p>
<ul>
<li>卡爾維諾的「<a target="_blank" href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010089497">如果在冬夜，一個旅人</a>」，是本講述一些人在讀小說的過程的小說，這叫 meta-fiction。</li>
<li>「我們手邊的使用者資料正確性有多高」這個數字，本身也是一個資料。所謂 meta-data，就是是關於資料的資料(data about data)。</li>
</ul>
<p>所以你現在一眼看到「<a target="_blank" href="http://zh.wikipedia.org/wiki/%E8%B7%AF%E4%BC%8A%E5%90%89%C2%B7%E7%9A%AE%E5%85%B0%E5%BE%B7%E5%A8%84">六個尋找作者的劇中人</a>」這個劇本，還有「<a target="_blank" href="http://www.books.com.tw/exep/prod/booksfile.php?item=0010518492">Design of design</a>」，就知道它們一付 meta 樣。</p>
<hr />
<p>回頭來看 meta-programming ，幫我們產生/修改程式的程式只是 meta-programming 的其中一部份而己。若用「關於程式的程式」來理解，「將程式碼本身當做資料在操作的程式」才是 meta-programming 的全貌。來個最近學到的超無用程式範例：</p>
<pre><code class="lang-ruby"><span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Suprise</span> &lt; (<span class="hljs-title">rand</span> &lt; 0.5 ? <span class="hljs-title">Hash</span> : <span class="hljs-title">Array</span>)</span>
<span class="hljs-keyword">end</span>

sup = Surprise.new
sup[<span class="hljs-number">0</span>] = <span class="hljs-string">'wow!'</span>
p sup <span class="hljs-comment">#可能是陣列 ["wow!"]，也可能是Hash { 0 =&gt; "wow!" }</span>
</code></pre>
<p>第一行的後半段，我們將 Hash 或是 Array 這兩個類別當做資料在操作，<code>Surprise</code>各有 50% 的機會繼承 <code>Hash</code> 或是 <code>Array</code>。我認為這是不產生/修改程式碼的 meta-programming 好範例。另外提一下，如果你在 production code 裡用了這個技巧，千萬不要說是我教你的。</p>
<p>看一下 JavaScript 這個對 meta-programming 非常友善的語言，由於物件跟 Hash 是同一種東西，因此我們把使用 <code>["string"]</code> 的形式動態的從物件中調值視為理所當然。在其它的語言中，這件事並非總是這麼簡單。</p>
<p>Ruby 還可以輕鬆的用 <code>send()</code> 解決:</p>
<pre><code class="lang-ruby">obj.send(<span class="hljs-symbol">:method_name</span>)
</code></pre>
<p>在 Java 裡就得大費周章的使用 <a target="_blank" href="http://java.sun.com/docs/books/tutorial/reflect/index.html">reflaction</a>:</p>
<pre><code class="lang-java">MyClass.class.getMethod(<span class="hljs-string">"methodName"</span>).invoke(someArgs)
</code></pre>
<p>再來看看 JavaScript 頗受壞評的 <code>eval</code>:</p>
<pre><code class="lang-js"><span class="hljs-built_in">eval</span>(<span class="hljs-string">"function magic(){ alert('rabbit!'); }"</span>);
magic();
</code></pre>
<p>所以當資料與程式碼的界限開始模糊的時候，你知道你已經跨進 meta-programming 的界限裡了。你也該知道，這一段程式碼要是出錯了，在 debug 時可能沒那麼容易。</p>
<hr />
<p>那時我回問了我朋友:「那你覺得有什麼比較好的翻法嗎?」朋友說：「我覺得翻成"元編程"跟"元資料"蠻不錯的。」
想了想，我也這麼覺得。</p>
]]></content:encoded></item><item><title><![CDATA[客製 Mac 的 CLI]]></title><description><![CDATA[UPDATE:
後來我改用 prezto 來取代 ohmyzsh，功能跟佈景主題比較少，但啟動速度較快.
Further Update:
再後來就用純 zshrc + zshenv 改了。可以參考 我的 dotfiles



之前答應的事欠很久，就用這篇來還吧。
身為 Ruby/Rails 開發者，每天跟 Command Line Interface (CLI) 混在一起是再正常也不過的了。
之所以買 Mac，就是因為 Mac 的 CLI 跟 Windows 渣一般的命令提示字元不是同一個等級...]]></description><link>https://taian.su/2013-06-06-mac-cli</link><guid isPermaLink="true">https://taian.su/2013-06-06-mac-cli</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Thu, 06 Jun 2013 00:42:00 GMT</pubDate><enclosure url="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271092094/e9116322-7abc-49a2-bb11-41374321c25f.jpeg" length="0" type="image/jpeg"/><content:encoded><![CDATA[<blockquote>
<p><strong>UPDATE</strong>:</p>
<p>後來我改用 <a target="_blank" href="https://github.com/sorin-ionescu/prezto">prezto</a> 來取代 ohmyzsh，功能跟佈景主題比較少，但啟動速度較快.</p>
<p><strong>Further Update:</strong></p>
<p>再後來就用純 zshrc + zshenv 改了。可以參考 <a target="_blank" href="https://github.com/taiansu/dotfiles">我的 dotfiles</a></p>
</blockquote>

<hr />
<p>之前答應的事欠很久，就用這篇來還吧。</p>
<p>身為 Ruby/Rails 開發者，每天跟 <a target="_blank" href="http://zh.wikipedia.org/wiki/%E5%91%BD%E4%BB%A4%E8%A1%8C%E7%95%8C%E9%9D%A2">Command Line Interface (CLI)</a> 混在一起是再正常也不過的了。</p>
<p>之所以買 Mac，就是因為 Mac 的 CLI 跟 Windows 渣一般的命令提示字元不是同一個等級的東西。即使如此，要是每次打開內建的終端機，都看到是下圖這個樣子，也很難不心生畏懼一下的。</p>
<p><a target="_blank" href="https://taiansu.micro.blog/uploads/2022/875b2e4113.jpg"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271092094/e9116322-7abc-49a2-bb11-41374321c25f.jpeg" alt="Original OSX CLI" /></a></p>
<p>既然是每天拿來吃飯的工具，我自己用了 iTerm2，Oh My ZSH，再選一個喜歡的 <a target="_blank" href="http://zh.wikipedia.org/wiki/%E7%AD%89%E5%AE%BD%E5%AD%97%E4%BD%93">monospace 字體</a>，把它弄成這樣:</p>
<p><a target="_blank" href="https://taiansu.micro.blog/uploads/2022/433f952d16.jpg"><img src="https://cdn.hashnode.com/res/hashnode/image/upload/v1685271094811/bfc46a1a-aa94-4862-a3ab-2b8808be4eda.jpeg" alt="Prettier OSX CLI" /></a></p>
<h2 id="heading-monospace">monospace 字體</h2>
<p>好用的 monospace 字體其實蠻多的，可以從<a target="_blank" href="http://www.slant.co/topics/67/~what-are-the-best-programming-fonts">這裡</a>挑一個。基本上就是 <code>1</code>，<code>l</code>，<code>I</code> 及 <code>0</code>，<code>o</code>，<code>O</code> 要分的清楚，其它就是個人喜好了。我目前用的是 Source Code Pro，之前則是 <a target="_blank" href="http://www.dafont.com/bitstream-vera-mono.font">Bitstream vara sans mono</a>。</p>
<h2 id="heading-iterm2">iTerm2</h2>
<p>iTerm2 不是必要的，但它提供了原生的 Terminal.app 所沒有的幾個好用功能：</p>
<ol>
<li><kbd>command</kbd> + click to open file</li>
<li>Split pane view</li>
<li>Hotkey Instant terminal anywhere</li>
<li>Highlight word when searching</li>
<li>Mouseless copy</li>
<li>Paste history</li>
</ol>
<p>到<a target="_blank" href="http://www.iterm2.com/downloads/stable/iTerm2_v1_0_0.zip">官網</a>下載後解壓縮，然後丟到 Application 裡。</p>
<p>執行 iTerm2，到 Preference 改 Profiles =&gt; Default =&gt; Text 選擇你剛裝好的字體。</p>
<h4 id="heading-6ycy6zqo6ieq6kic6yg46acf">進階自訂選項</h4>
<p><a target="_blank" href="http://color.smyck.org/">SMYCK</a>，<a target="_blank" href="https://github.com/rickharris/vim-railscasts">railscasts theme</a> 都是蠻不錯的配色。下載後點兩下匯入，再去 Preference 改 Profiles =&gt; Default =&gt; Colors。</p>
<h2 id="heading-oh-my-zsh">oh-my-zsh</h2>
<p>oh-my-zsh 讓你可以不用再辛苦的手刻 config file，就內建一堆好用的 plugin(*註)， 還提供一堆主題讓你挑選。因為我比較喜歡 zsh 的補完功能，如果你還是想用 Mac 預設的 bash，<a target="_blank" href="https://github.com/revans/bash-it">bash-it</a> 看來可以做到類似的事。但因為我沒用過，所以請自行踩雷。</p>
<p>安裝 oh-my-zsh 的方式，就是打開剛剛裝好的 iTerm2 ( Terminal.app 也可以)，貼上這行指令:</p>
<pre><code class="lang-bash">curl -L http://install.ohmyz.sh | sh
</code></pre>
<p>更多 Oh My ZSH 的設定可以參考 RailsCasts 的<a target="_blank" href="http://railscasts.com/episodes/308-oh-my-zsh">影片</a></p>
<h3 id="heading-6ycy6zqo6ieq6kic6yg46acf-1">進階自訂選項</h3>
<p>到 <a target="_blank" href="http://zshthem.es/all/">zshthem</a> 挑一個順眼的主題，記下上方的名字。(裡面沒有列出全部可用的主題，像是很多人愛用，但是需要特殊字體的 agnoster)。我用的是 af-magic。</p>
<p>修改 <code>~/.zshrc</code> ，把 <code>ZSH-THEME="xxxxx"</code> 的xxxxx改成你剛剛記下來的字，儲存。然後回到 iTerm2，輸入 <code>source ~/.zshrc</code></p>
<hr />
<p><strong>提醒</strong>：</p>
<ul>
<li><p><code>~/.zshrc</code> 底下的 <code>plugins="(.....)"</code> 千萬要慎選。看清楚 <code>~/.oh-my-zsh/plugins/</code> 裡的相應的檔案內容。我曾經被 bundler plugin 搞掉好幾個小時。</p>
</li>
<li><p>指令上色是用 <a target="_blank" href="https://github.com/zsh-users/zsh-syntax-highlighting">zsh-syntax-highlighting</a> 做的。 想要的話就參考連結裡的說明。</p>
</li>
</ul>
]]></content:encoded></item><item><title><![CDATA[在 OS X 安裝 git 環境]]></title><description><![CDATA[基本上就是某篇文章的片段翻譯。

I. 安裝 Command Line Tools
首先需要安裝 OSX Command Line Tools。
如果你沒有開發 iOS 或是 Mac App 的需求，可以直接到Apple developer site (免費，需註冊) 下載 Command Line Toos for Mountain Lion 並安裝，可以省下約 4GB 的空間。
若想安裝 Xcode，就照以下的步驟操作

開啟 App Store，搜尋 Xcode 再點安裝

執行 Xcod...]]></description><link>https://taian.su/2013-06-05-os-x-git</link><guid isPermaLink="true">https://taian.su/2013-06-05-os-x-git</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Wed, 05 Jun 2013 01:15:00 GMT</pubDate><content:encoded><![CDATA[<p>基本上就是<a target="_blank" href="/201210/setup-rails-environment-on-mountain-lion-from-scratch">某篇文章</a>的片段翻譯。</p>

<h2 id="heading-i-command-line-tools">I. 安裝 Command Line Tools</h2>
<p>首先需要安裝 OSX Command Line Tools。
如果你沒有開發 iOS 或是 Mac App 的需求，可以直接到<a target="_blank" href="https://developer.apple.com/downloads/index.action">Apple developer site</a> (免費，需註冊) 下載 Command Line Toos for Mountain Lion 並安裝，可以省下約 4GB 的空間。</p>
<p>若想安裝 Xcode，就照以下的步驟操作</p>
<ol>
<li><p>開啟 App Store，搜尋 Xcode 再點<kbd>安裝</kbd></p>
</li>
<li><p>執行 Xcode，在選單列依序點選<kbd>Xcode</kbd> -&gt; <kbd>preferences</kbd></p>
</li>
<li><p>切換到<kbd>Downloads</kbd> -&gt; <kbd>Components</kbd>分頁中。</p>
</li>
<li><p>按下<code>Command Line Tools</code>項目旁的<kbd>install</kbd>按鈕。</p>
</li>
</ol>
<h2 id="heading-ii-homebrew">II. 安裝 Homebrew 套件管理工具</h2>
<p><em>Homebrew</em> 是 OS X 上相當好用的套件管理員，可以想成是命令列版的 App Store 之類的。
安裝的方式是執行終端機。(在 Spotlight 裡輸入<code>terminal</code>就會找到了)
接著複製底下的命令，貼到終端機上，按<kbd>Enter</kbd>執行。</p>
<pre><code class="lang-bash">ruby -e <span class="hljs-string">"<span class="hljs-subst">$(curl -fsSkL raw.github.com/mxcl/homebrew/go)</span>"</span>
</code></pre>
<h2 id="heading-iii-homebrew-git">III. 用 Homebrew 安裝 git</h2>
<p>在終端機上輸入</p>
<pre><code class="lang-bash">brew install git
</code></pre>
<h2 id="heading-iv-git">IV. 設定 git 使用者</h2>
<p>在終端機上分別輸入以下兩行，記得把名字跟 email 改掉。</p>
<pre><code class="lang-bash">git config --global user.name <span class="hljs-string">"你的名字"</span>
git config --global user.email <span class="hljs-string">"你的Email"</span>
</code></pre>
<h2 id="heading-v">V. 錯誤訊息大逃殺</h2>
<p>請參考<a target="_blank" href="http://www.moncefbelyamani.com/how-to-install-xcode-homebrew-git-rvm-ruby-on-mac/">本篇</a></p>
]]></content:encoded></item><item><title><![CDATA[在 Linux 安裝 Rails 環境]]></title><description><![CDATA[安裝必要元件
開啟「終端機模擬程式」(在 Menu 裡)，分別輸入底下每一行指令後按Enter。先不要整塊複制貼上，得一行行輸入。如果指令很長懶得打的話，在 Linux裡開瀏覽器 (Menu -> 網際網路)，找這篇文章一步步複製貼上。

sudo apt-get update

按下Enter後會要求你輸入密碼，按密碼時螢幕沒有反應是正常的，就打進去按Enter。
sudo apt-get upgrade

完成後中間若有要求取代檔案的訊息，一直按Enter同意。
sudo apt-get i...]]></description><link>https://taian.su/2012-10-27-linux-rails</link><guid isPermaLink="true">https://taian.su/2012-10-27-linux-rails</guid><dc:creator><![CDATA[Tai An Su]]></dc:creator><pubDate>Fri, 26 Oct 2012 22:47:00 GMT</pubDate><content:encoded><![CDATA[<h2 id="heading-yuan">安裝必要元件</h2>
<p>開啟「終端機模擬程式」(在 Menu 裡)，分別輸入底下每一行指令後按<kbd>Enter</kbd>。先不要整塊複制貼上，得一行行輸入。如果指令很長懶得打的話，在 Linux裡開瀏覽器 (Menu -&gt; 網際網路)，找這篇文章一步步複製貼上。</p>

<pre><code class="lang-bash">sudo apt-get update
</code></pre>
<p>按下<kbd>Enter</kbd>後會要求你輸入密碼，按密碼時螢幕沒有反應是正常的，就打進去按<kbd>Enter</kbd>。</p>
<pre><code class="lang-bash">sudo apt-get upgrade
</code></pre>
<p>完成後中間若有要求取代檔案的訊息，一直按<kbd>Enter</kbd>同意。</p>
<pre><code class="lang-bash">sudo apt-get install curl build-essential zlib1g-dev libssl-dev libreadline-dev xclip git
<span class="hljs-built_in">echo</span> <span class="hljs-string">"alias clipboard='clip -sel clip'"</span> &gt;&gt; ~/.bashrc
</code></pre>
<p>上面的 zlib1g 請拼對，前面是<code>L</code>後面是<code>1</code>，在這裡卡關就太冤了。</p>
<hr />
<h2 id="heading-rbenv">安裝 rbenv</h2>
<p>首先安裝 rbenv</p>
<pre><code class="lang-bash">git <span class="hljs-built_in">clone</span> git://github.com/sstephenson/rbenv.git .rbenv
<span class="hljs-built_in">echo</span> <span class="hljs-string">"export PATH='<span class="hljs-variable">$HOME</span>/.rbenv/bin:<span class="hljs-variable">$PATH</span>'"</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">echo</span> <span class="hljs-string">'eval "$(rbenv init -)"'</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">exec</span> <span class="hljs-variable">$SHELL</span>
</code></pre>
<p>再安裝 ruby-build</p>
<pre><code class="lang-bash">mkdir -p ~/.rbenv/plugins
<span class="hljs-built_in">cd</span> ~/.rbenv/plugins
git <span class="hljs-built_in">clone</span> git://github.com/sstephenson/ruby-build.git
<span class="hljs-built_in">echo</span> <span class="hljs-string">'export PATH="$HOME/.rbenv/plugins/ruby-build/bin:$PATH"'</span> &gt;&gt; ~/.bashrc
<span class="hljs-built_in">exec</span> <span class="hljs-variable">$SHELL</span>
</code></pre>
<p>總算要開始裝 Ruby 跟 Rails 了。</p>
<pre><code class="lang-bash">rbenv install 2.1.2
rbenv <span class="hljs-built_in">rehash</span>
rbenv global 2.1.2
ruby -v
gem install bundler rails
rbenv <span class="hljs-built_in">rehash</span>
rails -v
</code></pre>
]]></content:encoded></item></channel></rss>