<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom">
  <id>https://gugod.org/</id>
  <title>gugod's blog</title>
  <link rel="alternate" href="https://gugod.org" type="text/html"/>
  <entry>
    <id>https://gugod.org/2024/06/perlclass-first-explore-monty-hall-game-simulation/?d6cf57f1a75e2a43d3868af51c9ab5a2cefd9751</id>
    <link rel="alternate" href="https://gugod.org/2024/06/perlclass-first-explore-monty-hall-game-simulation/" type="text/html"/>
    <title>perlclass 初探: 以模擬 Monty Hall Problem 為例</title>
    <published>2024-06-09T23:01:41+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Monty Hall Problem （<a href="https://zh.wikipedia.org/zh-tw/%E8%92%99%E6%8F%90%E9%9C%8D%E7%88%BE%E5%95%8F%E9%A1%8C">蒙提霍爾問題</a>）是個奇妙而有趣的數學遊戲問題。維基百科上提供的問題本文為：
</p>
        <blockquote>
          <p>假設你正在參加一個遊戲節目，你被要求在三扇門中選擇一扇：其中一扇後面有一輛車；其餘兩扇後面則是山羊。你選擇了一道門，假設是一號門，然後知道門後面有什麼的主持人，開啟了另一扇後面有山羊的門，假設是三號門。他然後問你：「你想選擇二號門嗎？」轉換你的選擇對你來說是一種優勢嗎？
</p>
        </blockquote>
        <p>此問題的解答是「會」，也就是換答案後會比較容易得到汽車的意思。
</p>
        <p>但，這答案是以列舉出幾種狀況的機率來比較而得的。以機率而論，如果我能玩這遊戲 1000 次，那麼每一局都依主持人提供的資訊來更換答案後，我能在這 1000 局內獲勝的總次數較多。期望值約為 1000 <em> 2/3，也就是約為 666 次。而如果我每一局都不換答案，那我在這 1000 局內的獲勝期望值則為 1000 </em> 1/3，也就是約為 333 次。
</p>
        <p>既然如此，那就必須寫個程式來模擬看看了。以下是 <a href="https://github.com/gugod/bin/blob/master/play-monty-hall.pl">play-monty-hall.pl</a> ，以 <a href="https://perldoc.perl.org/perlclass">perlclass</a> 提供的新語法寫成的一個模擬程式，可模擬兩種策略玩家在玩了多局之後的勝率。雖然沒有註解，但應該還算是能夠望文生義的程度。
</p>
        <pre>
          <code>#!/usr/bin/env perl
use v5.38;
use feature 'class';
no warnings 'experimental::class';

class Game {
    field $doors :param;
    field $winningDoor = 1 + int rand($doors);

    method doors { $doors }
    method winningDoor { $winningDoor }

    method loosingDoors {
        grep { $_ != $winningDoor } (1..$doors);
    }
};

class FirstChoicePlayer {
    field $doors :param;
    field $firstChoice = 1 + int rand($doors);
    field @loosingDoors;

    method doors { $doors }
    method addLoosingDoors ($n) { push @loosingDoors, $n }
    method loosingDoors () { @loosingDoors }
    method firstChoice () { $firstChoice }
    method finalChoice () { $firstChoice }
};

class ChangeChoicePlayer :isa(FirstChoicePlayer) {
    method finalChoice () {
        my %isLoosing = map { $_ =&gt; 1 } $self-&gt;loosingDoors();
        my @choices = grep { $_ != $self-&gt;firstChoice() } grep { ! $isLoosing{$_} } 1..$self-&gt;doors();

        die "Illegal state" if @choices != 1;
        return $choices[0];
    }
};

class GameMaster {
    field $doors :param;
    method playWith ($player) {
        die "No player ?" unless defined $player;

        my $game = Game-&gt;new( doors =&gt; $doors );

        my %untold = map { $_ =&gt; 1 } ($game-&gt;winningDoor, $player-&gt;firstChoice);
        while ((keys %untold) == 1) {
            my $door = 1 + int rand($doors);
            $untold{$door} = 1;
        }
        my @revealLoosingDoors = grep { ! $untold{$_} } (1..$doors);

        for my $door (@revealLoosingDoors) {
            $player-&gt;addLoosingDoors($door)
        }

        my $finalChoice = $player-&gt;finalChoice();

        return $finalChoice == $game-&gt;winningDoor;
    }
};

sub playOneRound($playerClass) {
    my $doors = 3;
    my $gm = GameMaster-&gt;new( doors =&gt; $doors );
    my $player = $playerClass-&gt;new( doors =&gt; $doors );
    return $gm-&gt;playWith( $player );
}

sub play ($rounds, $playerClass) {
    my $wins = 0;
    for (1 .. $rounds) {
        my $win = playOneRound($playerClass);
        $wins++ if $win;
    }
    return $wins;
}

sub sim ($rounds) {
    for my $playerClass ("FirstChoicePlayer", "ChangeChoicePlayer") {
        my $wins = play($rounds, $playerClass);
        my $pWin = $wins / $rounds;
        say "$playerClass wins $wins / $rounds. p(win) = $pWin";
    }
}

sim(shift // 1000);
</code>
        </pre>
        <p>可以提供一個參數，表示要模擬幾局。預設為 1000 局。執行起來如下：
</p>
        <pre>
          <code># play-monty-hall.pl
FirstChoicePlayer wins 323 / 1000. p(win) = 0.323
ChangeChoicePlayer wins 665 / 1000. p(win) = 0.665

# play-monty-hall.pl 1000000
FirstChoicePlayer wins 333606 / 1000000. p(win) = 0.333606
ChangeChoicePlayer wins 666348 / 1000000. p(win) = 0.666348</code>
        </pre>
        <p>這程式內主要幾個互相作用的 class:
</p>
        <ul>
          <li><code>FirstChoicePlayer</code>: 以不變為其策略的玩家
</li>
          <li><code>ChangeChoicePlayer</code>: 以改變為其策略的玩家
</li>
          <li><code>GameMaster</code>: 與玩家互動的遊戲主持人。
</li>
          <li><code>Game</code>: 維護單一一局的遊戲初始資訊。基本上只有記住哪號門是贏門 (<code>$winnigDoor</code>)，並提供列舉出所有輸門的方法 <code>loosingDoors</code>
</li>
        </ul>
        <p>Game 物件在建構、初始完畢後計基本上是個常數了，沒有什麼特別的地方。 FirstChoicePlayer 也差不多，只是會有個 <code>@loosingDoors</code> 內部狀態來記著那些由 GameMaster 提供的輸門號碼。
</p>
        <p>而此處我讓 <code>ChangeChoicePlayer</code> 為 <code>FirstChoicePlayer</code> 的延伸，依照 <code>$self-&gt;firstChoice</code> 與 <code>$self-&gt;loosingDoors</code> 的內容來推算出 <code>finalChoice</code>。這邊我原本以為透過繼承機制，<code>FirstChoicePlayer</code> 的兩個 <code>field</code> 變數都可以直接在 <code>ChangeChoicePlayer</code> 內來使用。但結果是不行，必須在透過 <code>FirstChoicePlayer</code> 內定義的 getter method 才行。這表示由 <code>field</code> 所定義出來的便是是私有於該類別而已。
</p>
        <p>在所有類別中有一項共同參數 <code>$doors</code>，也就是這遊戲的門的數量。<code>Game</code> 類別是依 <code>$doors</code> 來隨機生成出贏門的號碼。兩個玩家類別內則是以數字去隨機產生 <code>firstChoice</code>。<code>GameMaster</code> 類別則是以此資訊來建構先的 <code>Game</code> 物件，還有推算出能告訴玩家哪些門是輸門。這邊我用了  <code>:param</code> 這個添在 <code>field</code> 變數上的屬性 (<code>field $doors :param;</code>)，來代表說這 <code>field</code> 的值必須被提供給類別的建構函式 <code>new</code>。這用法尚算直覺。而其他依賴 <code>$doors</code> 的值所計算出來的各 <code>field</code> 都似乎是正確地在物件建構時期被計算完畢了。無須另外調整。
</p>
        <p>目前幾個有需要用到的 getter method 都是我自己手動補上的，讓程式碼看來量很多。但依 <a href="https://perldoc.perl.org/perlclass#TODO">perlclass 文件中 TODO 一節</a> 內的說明，看來以後能寫個 <code>:reader</code> 來讓 perl 自動生成出 getter method。就能省下不少打字的力氣。
</p>
        <p>雖然 perlclass 語法跟類別機能十分基本，比不上其他以物件導向為核心設計的語言。但以這個小程式的用途用起來沒意外，很夠用。等以後改版之後再來看看有沒有什麼更有意思的地方。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2024/02/yapc-hiroshima/?6ae81d7ea6f7f642f3cad0128831d1e30c53eddb</id>
    <link rel="alternate" href="https://gugod.org/2024/02/yapc-hiroshima/" type="text/html"/>
    <title>YAPC::Hiroshima 2024 之行</title>
    <published>2024-02-14T22:01:13+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>這一次的 YAPC Japan 是辦在廣島國際會議中心，位於和平紀念公園內，離原爆圓頂館很近。雖然離市中心區有一小段距離，但走起來並不算遠。
</p>
        <p>比起去年的 YAPC::Kyoto，這次的活動規模似乎擴大了。贊助商數竟然超過 50 家，而且有八間是廣島當地的中小企業。這還真是令人驚訝。
</p>
        <p>不過這次的議程，在內容方面與 Perl 直接相關的已經減少到一半左右了，可能算是有些偏離主體？但儘管如此，技術方面的主題仍然挺吸引人，並且技術知識的共享方面是共通的。似乎可以不必計較。
</p>
        <p>贊助商的攤位方面，有十來間到場設攤宣傳的廠商。另我印象比較深刻的是 chocoZAP 這個主打用零碎時間來運動的輕度健身的品牌，竟然也是贊助商（其公司為 RIZAP）。而且也在現場招募。從宣傳單上看來，伺服器端是 Ruby，iOS App 為 Swift，Android 為 Kotlin 這樣的組合吧。宣傳單的背面則是拉人加入健身房會員的廣告了(附折扣碼)（笑）。
</p>
        <p>另一間另我印象深刻的是 Findy。其主產品是協助軟體團隊能理解開發現況的視覺化輔助工具。跟我在碩士班期間做的題目很像。能給一個團隊一些簡明的圖表來迅速看出目前專案開發的狀態，瓶頸之有無，人員協作的連結度等等。應該比較偏向是給管理階級的人員看的圖資工具。
</p>
        <p>議程本體方面，總共分成三軌，自然也是等日後看有沒有錄影可以補完。在此先大致上摘要了一些我現場聽到覺得有意思的內容。
</p>
        <p>〈VISAカードの裏側と “手が掛かる” 決済システムの育て方 by 三谷〉。講者是在 VISA 發卡公司員工。這演講算是業界甘苦談吧。難度核心部份在於要能夠「寬鬆而有彈性地」去處理由 VISA API 呼過來的各種不太合理的內容。講者宣稱在聽完後，大家之後必定會在拿到刷卡對帳單時好好看一下在那張小單據印上的各欄資訊。這是真的。
</p>
        <p>〈rakulangで実装する! RubyVM by 八雲アナグラ〉。講者探索了如何以 rakulang 製作一個簡單的 Ruby VM，並分享了其摘要。嚴格說起來他做的程式不算是 Ruby VM，因為不能吃 bytecode，只能吃文字格式的組語。但要做出 YARV bytecode 似乎不那麼容易，所以就退而求其次了。是深入淺出，內容豐富的演講。
</p>
        <p>〈PerlでつくるフルスクラッチWebAuthn/パスキー認証 by macopy〉。講者用 live coding 形式說明了 WebAuthn 協定。概要清晰，有把 WebAuthn 中幾個重點都解釋出來。live coding 最後也成功了。但看來有 80% 左右的程式碼是 Copilot 寫的啊。 （結果 ok 就好）
</p>
        <p>Keynote 由「とほほのWWW入門」這個網站的作者「杜甫々」來登台。看來是位人人皆知的名人，這網站上所有文件似乎都是他自己編寫的，種類眾多，從軟體技術細節到所得稅法都有著墨。真是不得由衷讓人欽佩：怎麼會有人這麼會寫文件？
</p>
        <p>伴隨研討會的舉行，同時這次由面白法人主催了個 perlgolf 活動。很久沒玩了，還是頂懷念這種看似胡搞，但卻又能確實達成目的且節節變難的重構過程啊。同時也有種：「這才是 Perl 研討會啊！」的一種爽快感。雖然實務上不會有要把程式碼節節縮短的需要，但對同一個問題反覆進行重構、不斷得出不同風格的解法，不也是一種解決問題所必備的基礎能力嗎？
</p>
      </div>
    </content>
    <category term="yapcjapan"/>
    <category term="hiroshima"/>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/12/perl-5-38-2-5-36-3-5-34-3-released/?aaea9add779636c7a9b58baf1d5861af0026cac7</id>
    <link rel="alternate" href="https://gugod.org/2023/12/perl-5-38-2-5-36-3-5-34-3-released/" type="text/html"/>
    <title>perl 5.38.2、5.36.3、5.34.3 三個版本的釋出</title>
    <published>2023-12-03T10:12:43+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>最近注意到有三個新版連發：
</p>
        <ul>
          <li><a href="https://metacpan.org/release/PEVANS/perl-5.38.2/changes">https://metacpan.org/release/PEVANS/perl-5.38.2/changes</a>
</li>
          <li><a href="https://metacpan.org/release/PEVANS/perl-5.36.3/changes">https://metacpan.org/release/PEVANS/perl-5.36.3/changes</a>
</li>
          <li><a href="https://metacpan.org/release/PEVANS/perl-5.34.3/changes">https://metacpan.org/release/PEVANS/perl-5.34.3/changes</a>
</li>
        </ul>
        <p>但是內容都一樣，看來是專門為了處理以下兩個 CVE 而發的新版本：
</p>
        <ul>
          <li>CVE-2023-47038 - Write past buffer end via illegal user-defined
Unicode property
</li>
          <li>CVE-2023-47039 - Perl for Windows binary hijacking vulnerability
</li>
        </ul>
        <p>CVE-2023-47038 的影響範圍是自 5.30.0 (釋出日為 2019/05/22) 到 5.38.0 （釋出日為 2023/07/02）。這範圍不小，得來升級一下。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/07/tprc-2023-toronto/?504bee37be29f906670e69cce7256c2a9bcd08e5</id>
    <link rel="alternate" href="https://gugod.org/2023/07/tprc-2023-toronto/" type="text/html"/>
    <title>TPRC 2023 與多倫多之旅</title>
    <published>2023-07-17T19:59:31-04:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="html" xml:base="https://gugod.org">&lt;p&gt;TPRC 2023 Toronto 的錄影已陸續釋出，可於 youtube 上觀看: &lt;a href="https://www.youtube.com/playlist?list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa"&gt;https://www.youtube.com/playlist?list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;TPRC -- The Perl and Raku Conference. 現在在日本以外的其他地方都是用這幾個字來稱呼 Perl &amp;amp; Raku 研討會了。但基本上 YAPC 跟 TPRC 這兩個名字指的都是由社群主辦的，主題包含 Perl 的研討會。
&lt;/p&gt;&lt;p&gt;雖然跑了不少地方的 Perl 研討會，但上次去到北美地區參與與 Perl 有點關係的研討會已經是 2004 年的 OSCON。芥於我還沒去踩過 &amp;quot;YAPC::NA&amp;quot; 這個領域，就想說就去看看吧。順便與那些社群舊友、網友、「GitHub PR 友」碰個面也好。
&lt;/p&gt;&lt;p&gt;TPRC 議程共有三日，議程共有三軌並行，儘量參加，但必定有三分之二是只能看錄影了。除了常規議程以外，與新舊朋友在午餐時間社交，也是這研討會的重點。讓我回想到以前的 YAPC::Taipei 與 OSDC 的那幾年了。先推薦幾場我有在座聽完的演講：
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;The Test2 Ecosystem - Chad Granum. &lt;a href="https://youtu.be/7lNtM2FmTow"&gt;https://youtu.be/7lNtM2FmTow&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;Lingy &amp;amp; YAMLScript - News Ways to Program Perl - Ingy döt؜؜ Net. &lt;a href="https://youtu.be/9OcFh-HaCyI"&gt;https://youtu.be/9OcFh-HaCyI&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="https://tprc2023.sched.com/event/1LhoB/the-n-queens-problem-by-regexp"&gt;The N-Queens problem by Regexp - Abigail.&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="https://tprc2023.sched.com/event/1NIEZ/screwdriver-included-making-your-project-easier-to-enhance-and-extend"&gt;Screwdriver Included: Making your project easier to enhance and extend&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;演講主題形形色色，很容易就讓人聯想到多倫多市內 &lt;a href="https://en.wikipedia.org/wiki/Kensington_Market"&gt;Kensington Market&lt;/a&gt; 這區，裡面什麼樣的店都有。有滿足日間觀光客的小吃、咖啡店，也有讓當地居民能購物的生鮮市場，更有能滿足拍照欲望的街頭藝術。
&lt;/p&gt;&lt;p&gt;
&lt;a data-flickr-embed="true" data-header="true" data-footer="true" href="https://www.flickr.com/photos/gugod/53071999920/in/dateposted/" title="The Car"&gt;&lt;img src="https://live.staticflickr.com/65535/53071999920_d78d4a0c36.jpg" width="376" height="500" alt="The Car"/&gt;&lt;/a&gt;
&lt;br&gt;
Kensington Market 內的地標。聽說常常換「新車」。&lt;/p&gt;
&lt;p&gt;多倫多是個很大的都會區。雖然在此行之前從沒去過而讓人擔心，但從地圖上滿滿的公車站、地鐵站、路面電車，與密密麻麻的路線圖這一點看來，在市區內移動絕對不成問題。確實也是如此。一出 YYZ 機場，在售票機買了張 Presto 卡之後，就可以靠這張卡搭車移動。準備零錢也可以，但刷卡進出簡單多了。缺點是 6 CAD 的購卡費用與其中儲值金都不能退。考慮到以 Presto 乘車費用略為便宜一些，多乘幾趟就能把這 6 CAD 攤平，就決定買來用了。
&lt;/p&gt;&lt;p&gt;多倫多市內商業區都是超級高樓，之外則都是三層樓左右的矮房。拍街景時，很容易取到以巨大建築為背景的構圖。走在街上，有時會把遠方的高樓誤以為是山脈一般的錯覺。並且，無論怎麼走，都可以遇到大小工地，要不就是拆建房屋，要不就是修改馬路。工人們直接穿著作業服、戴著工地安全帽搭乘地鐵的姿態隨時隨處可見。多倫多市區是個正在經歷都市更新、新舊混合中的地方。
&lt;/p&gt;&lt;p&gt;
&lt;a data-flickr-embed="true" data-header="true" data-footer="true" href="https://www.flickr.com/photos/gugod/53071512286/" title="聖彌額爾聖殿主教座堂"&gt;&lt;img src="https://live.staticflickr.com/65535/53071512286_0ba7269574.jpg" width="376" height="500" alt="聖彌額爾聖殿主教座堂"/&gt;&lt;/a&gt;
&lt;br&gt;
聖彌額爾聖殿主教座堂。攝於 2023 年 7 月 13 日。與 &lt;a href="https://www.google.com/maps/@43.6545776,-79.377598,3a,75y,29.85h,115.55t/data=!3m8!1e1!3m6!1s1p_APRSt4tY99beqqvWqvA!2e0!5s20210901T000000!6shttps:%2F%2Fstreetviewpixels-pa.googleapis.com%2Fv1%2Fthumbnail%3Fpanoid%3D1p_APRSt4tY99beqqvWqvA%26cb_client%3Dmaps_sv.tactile.gps%26w%3D203%26h%3D100%26yaw%3D20.790518%26pitch%3D0%26thumbfov%3D100!7i16384!8i8192?entry=ttu"&gt;2021 年 9 月 Google 街景圖&lt;/a&gt;相比後，明顯可看到後方兩棟這三年蓋起來的。&lt;/p&gt;
&lt;p&gt;Perl 程式語言，也正在經歷一段「都更」的過程。有很多新的機能出現之時，每項更新提案都會碰到現有居民的阻抗、競爭、妥協等等。就算是看來能帶來很美好的未來的提案，在有許多與現有生態相容議題要照顧的前提之下，未必都是能立刻成行的。有時就是得等到現有生態系消失了，阻力才會消退。雖然這也算是合情合理，但也造成了不少挫折。
&lt;/p&gt;&lt;p&gt;最近釋出的 perl 5.38 內所包含的 perl class，似乎相對來說是比較沒有阻礙的。畢竟，在物件導向概念風行了這麼久之後，大家對類別、物件等等的概念都有充分了解了，也就不會反對了。但即便如此，perl class 仍是個實驗性機能，一方面是因為幾位作者認為目前實做尚未完備，另一方面是因為大家已經習慣了將新機能以實驗性機能來推出的這個做法。
&lt;/p&gt;&lt;p&gt;無疑，Perl 社群是個很注重相容性的群體。
&lt;/p&gt;&lt;p&gt;儘管如此，仍有很多人在努力地替這老屋翻新。&lt;a href="https://www.youtube.com/watch?v=uT0S-jfO1mE&amp;amp;list=PLA9_Hq3zhoFwrDiojWd_lFUaOHlsUUEJa&amp;amp;index=10"&gt;Curtis 在他的主講&lt;/a&gt; 內提到了 &lt;a href="https://github.com/Perl-Oshun/oshun"&gt;Project Oshun&lt;/a&gt;、是繼 perl class 後以 Damian Conway 所設計的 &lt;a href="https://ovid.github.io/articles/language-design-consistency.html"&gt;KIM 語法&lt;/a&gt;去給變數與函數加上 data check （資料檢查、資料驗證）的機制。類似「型別」的概念。
&lt;/p&gt;&lt;p&gt;以下這段範例取自 Project Oshun。是以 &lt;code&gt;:returns&lt;/code&gt; 與 &lt;code&gt;:of&lt;/code&gt; 來標示出對函式與變數值的檢查規則。
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;sub fibonacci :returns(UINT) ($nth :of(PositiveInt)) {
    ...
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;或許目前 perl 5.38 這語言就像是照片中前方的那聖彌額爾聖殿主教座堂，雖然顯舊，但在各方面都已經盡善盡美了。只是，如果不經歷一番改建，是無法再度像四周的高樓大廈那般，成為充滿新機會的場所。而要如何妥善地將這場所慢慢改築成更加便利、更有效率、更加親切的高科技教堂，則是目前 Perl 社群面對的議題了。
&lt;/p&gt;&lt;p&gt;&lt;a href="https://youtu.be/B2X_caTDcAI"&gt;Sawyer 在對 Perl 7 這個題目反省時&lt;/a&gt;，提到了他自認有溝通不足的狀況。溝通管道眾多，也不容易全數照顧到。對於&lt;a href="https://youtu.be/Q1H9yKf8BI0"&gt;他收到太多攻擊性言語而決意離開這事&lt;/a&gt;，我覺得太可惜，也太糟糕了。不過另一方面，我覺得他還是別再來這沱爛泥內攪和比較好。至少，每個人都應把自己的時間花在自認最值得的地方。
&lt;/p&gt;&lt;p&gt;顯然，網路言論環境的維護，是 Perl 社群更該努力處理的議題。不然，能在這個環境中存活下來的，就只是一些很會講髒話的人了。
&lt;/p&gt;&lt;p&gt;&lt;script async charset="utf-8" src="//embedr.flickr.com/assets/client-code.js"&gt;&lt;/script&gt;
&lt;/p&gt;</content>
    <category term="tprc2023"/>
    <category term="tprc"/>
    <category term="yapc"/>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/07/perl-5.38.0-released/?24502dec002e6b4c6a95b6559127448f0e0bde0c</id>
    <link rel="alternate" href="https://gugod.org/2023/07/perl-5.38.0-released/" type="text/html"/>
    <title>perl 5.38.0 釋出</title>
    <published>2023-07-03T11:47:37+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>perl-5.38.0 變更說明： <a href="https://metacpan.org/release/RJBS/perl-5.38.0/changes">https://metacpan.org/release/RJBS/perl-5.38.0/changes</a>
</p>
        <p>摘要：
</p>
        <ul>
          <li>內建的物件導向架構的改善：新增 <code>class</code>, <code>field</code>, <code>method</code> 三個定義類別的關鍵字。（實驗性機能。須以 <code>use feature 'class';</code> 打開。）
</li>
          <li>新增對 Unicode 15.0 的支援。
</li>
          <li>新增：讓 <code>PERL_RAND_SEED</code> 環境變數為程式開跑時的亂數種子值。相當於去呼叫 <code>srand()</code> 。
</li>
          <li>讓語法錯誤訊息更加精簡。
</li>
          <li>自動在模組源碼 (內含 <code>package</code> 或 <code>class</code> 的 <code>.pm</code> 檔案) 最後補上 <code>true</code>
</li>
          <li>內部用的函式的移除與其文件改善。
</li>
          <li>宣告廢棄：smartmatch (given / when)。名稱空間中的 <code>'</code> 分隔符號。
</li>
        </ul>
        <h2>內建的物件導向架構的改善
</h2>
        <p>這應該是這是兩三年來著力最多的部份吧。比起多數提供在 CPAN 上的 OO 框架，perlclass 相對來說很好懂。有三個新的關鍵字與其帶來的新語意，但是幾乎沒有新的語法規則，至少目前沒有。
</p>
        <p>參考：<a href="https://metacpan.org/release/RJBS/perl-5.38.0/view/pod/perlclass.pod">perlclass</a> 文件。
</p>
        <p>三個新關鍵字是：<code>class</code>、<code>method</code>、<code>field</code>。<code>class</code> 用來定義類別。<code>method</code> 用來定義 instance method，<code>field</code> 用來宣告 instance variable。
</p>
        <p>以 <code>class</code> 定義出來的類別會自動以 <code>new</code> 為其 constructor 函式，並且，所有 instance method 體內皆能以 <code>$self</code> 表示目前物件。class 體內的 instance method 的 signature 則不可包含 <code>$self</code>。
</p>
        <p>而 <code>class</code> 體內的 <code>sub</code> 可用來定義 class method， <code>class</code> 體內的 <code>my</code> 則可用來宣告 private class variable。 <code>class</code> 體內的 <code>our</code> 則可用來宣告 public class variable。
</p>
        <p>在同一 <code>class</code> 體內以 <code>my</code>、<code>our</code>、<code>field</code> 宣告出來的諸變數是共用同一個名稱空間的。名稱有衝突的話，只有最後一個變數會被留下。
</p>
        <p>在同一 <code>class</code> 體內以 <code>sub</code> 與 <code>method</code> 宣告出來的各函式也是共用同一個名稱空間的。名稱有衝突的話，只有最後一個函式會被留下。
</p>
        <p>以 <code>field</code> 宣告出來的變數為 instance variable，只能被用於 instance method 體內。
</p>
        <p>以 <code>method</code> 定義出來的函式為 instance method，體內可使用 instance variable，同時亦會自動有 <code>$self</code> 可用來代表目前物件。要呼叫其他同一 class 內的 class method 的寫法與普通函式呼叫相同。要呼叫 instance method 時則是需要對 <code>$self</code> 呼叫。
</p>
        <p>當做範例，以下是一個描述了五段變速電風扇的簡易類別。
</p>
        <pre>
          <code>use v5.38;
use feature 'class';
use builtin 'true', 'false';

class Fan {
    use List::Util qw(min max);

    my $__id = 1;
    my $RPM_MAX  = 600;
    my $RPM_MIN  = 100;
    my $RPM_STEP = 100;

    sub vendor { "Cool Company" }
    sub speeds { ($RPM_MAX - $RPM_MIN ) / $RPM_STEP }

    field $id = $__id++;
    field $rpm = 3600;
    field $on = false;

    method id { $id }
    method speed { $rpm / $RPM_STEP }

    method turn_on  { $on = true }
    method turn_off { $on = false }
    method faster   { $rpm = min($rpm + $RPM_STEP, $RPM_MAX) }
    method slower   { $rpm = max($rpm - $RPM_STEP, $RPM_MIN) }

    method TO_JSON {
        +{
            # instance method / variable
            id      =&gt; $self-&gt;id(),
            speed   =&gt; $self-&gt;speed(),
            on      =&gt; $on,

            # class method / variable
            vendor  =&gt; vendor(),
            speeds  =&gt; speeds(),
            rpm_max =&gt; $RPM_MAX,
            rpm_min =&gt; $RPM_MIN,
        }
    }
}</code>
        </pre>
        <p>前述以 <code>sub</code> 定義出來的 class method，其實也可以被當成是 instance method 來呼叫。例如 <code>Fan</code> 類別的 <code>vendor</code> ，有兩種呼叫方式：
</p>
        <pre>
          <code>my $fan = Fan-&gt;new;

say $fan-&gt;vendor(); # (1)
say Fan-&gt;vendor();  # (2)</code>
        </pre>
        <p>(1) 與 (2) 兩處對應到的函式是同一個。
</p>
        <p>以 <code>class</code> 所附的 <code>new</code> 函式所做出來物件，字串形式上會有個 OBJECT 字樣：
</p>
        <pre>
          <code>my $fan = Fan-&gt;new;
say "$fan";

#=&gt; Fan=OBJECT(0x19477b0);</code>
        </pre>
        <p>如果是以常見的 blessed HashRef 做法 (即：<code>bless {}, 'Fan'</code>) 所造出來的物件，其字串形式是這樣：
</p>
        <pre>
          <code>Fan=HASH(0x1b3a5e8)</code>
        </pre>
        <p>由此可窺知在 perl 內部多了一種以 OBJECT 為表記的值。
</p>
        <h2>自動在模組源碼最後補上 <code>true</code>
</h2>
        <p>以往都要在 <code>.pm</code> 檔案最後補個 <code>1;</code>，然後還得向人說明這行看似無作用的程式碼的用途。以後在開頭加上 <code>use v5.38;</code> 後就不必在檔尾補 <code>1</code> 了。
</p>
        <pre>
          <code># Foo.pm
use v5.38;
package Foo {
    sub foo() { "Bar" }
}</code>
        </pre>
        <p>附帶一提，就算在最後在 Foo.pm 最後故意加上 <code>0;</code>，也不會讓 <code>use Foo;</code> 失敗。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/06/perl-safe-navigation-monad/?b4ba561110159ff157f8e7e5f45308a4428d6cd5</id>
    <link rel="alternate" href="https://gugod.org/2023/06/perl-safe-navigation-monad/" type="text/html"/>
    <title>[Perl] 以 Monad 來達成 safe navigation</title>
    <published>2023-06-18T17:02:02+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>在 reddit.com/r/perl 板上看到 pmz 問了這樣子的一個問題：
</p><blockquote>
<p>XML::Twig, get value (or not) without dying</p>
<p>Currently I do:</p>
<code><pre>
if (defined $elt-&gt;first_child('addr')-&gt;first_child('postalCode')) {
  $patient{patient_postal_code} = $elt-&gt;first_child('addr')-&gt;first_child('postalCode')-&gt;text ;
}
</pre></code>
<p>because if I don't check for "defined" and the resulting value is null , it dies.</p>
</blockquote>
<p>原文連結： <a href="https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/">https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/</a>
</p><p>這一方面是在針對 XML::Twig 模組的用法提問，另一方面是在問：當 <code>first_child('addr')</code> 傳回 <code>undef</code> 時，表示在目前 XML 文件樹中沒有 <code>addr</code> 元素，而後o方的連環呼叫 <code>first_child('postalCode')</code> 之處就會讓程式執行中斷，因為原本預期是物件的地方，也有可能是 <code>undef</code>。那有沒有能讓連環呼叫不會使程式失敗，並且在遇到 <code>undef</code> 時，讓整串算式的結果成為 <code>undef</code> 的辦法？
</p><p>如果把題目重新描述得較抽象一些的話，就是：假設有一類別，其下有方法 <code>a()</code>、<code>b()</code>、<code>c()</code>。這三個方法可能會傳回 <code>undef</code> 或同一類別的物件。今有一物件 <code>$o</code> 屬此類別，考慮此連環呼叫式：
</p><pre><code>$res = $o-&gt;a()-&gt;b()-&gt;c();
</code></pre><p>此式在 <code>a()</code> 或 <code>b()</code> 傳回 <code>undef</code> 時，就會讓程式中斷，並會出現像這樣的錯誤訊息：
</p><pre><code>Can't call method "c" on an undefined value
</code></pre><p>亦即：無法對 <code>undef</code> (undefined value) 呼叫 "c" 這個方法。這是當然的，因為 <code>undef</code> 並非物件。
</p><p>試問：有何手段能改寫此式，能避免前述錯誤之發生，使 <code>$res</code> 在  <code>a()</code>、<code>b()</code>、<code>c()</code> 任一者傳回 <code>undef</code> 時就算得 <code>undef</code>，且在全無 <code>undef</code> 情況下，又能正確算得 <code>c()</code> 的傳回值？
</p><p>在一些語言中，這可輕易得透過使用 safe-navigation operator 或 optional chaining operator 來解決。例如 javascript 或 kotlin 中的 <code>?.</code>：
</p><pre><code>res = o.a()?.b()?.c();
</code></pre><p>又例如 raku 語中的 <a href="https://docs.raku.org/language/operators#methodop_.%3F"><code>.?</code></a>:
</p><pre><code>$res = $o.a().?b().?c();
</code></pre><p>但直到目前 perl 5.38 為止，在 perl 語言中尚未出現同等作用的算符。
</p><p>有個直觀的改寫方式是像這樣：
</p><pre><code>$res_a = $o-&gt;a();
$res_b = $res_a &amp;&amp; $res_a-&gt;b();
$res   = $res_b &amp;&amp; $res_b-&gt;c();
</code></pre><p>但在讓程式變長、用了多個臨時變數而讓程式碼變得稍微不好讀之外，這改寫法還不通用，碰到類似結構、名稱不同的式子就得手動從頭改寫。實在算不上是好辦法。
</p><p>此外，有個超間單的改寫方法：
</p><pre><code>$res = eval { $o-&gt;a()-&gt;b()-&gt;c() };
</code></pre><p>但是，這個寫法的副作用，就是所有例外事件通通都會被忽略，雖然簡單好改，但其副作用很強。不見得在各種情境都適合。
</p><p>在此提供一個以 Monad Design Pattern 來達成得的一個解法。
</p><p>改寫方法如下：
</p><pre><code>$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap();
</code></pre><p>其中 <code>SafeNav</code> 的定義為：
</p><pre><code>use v5.36;
package SafeNav {
    sub wrap ($class, $o) { bless \$o, $class }
    sub unwrap ($self)    { $$self            }

    sub AUTOLOAD {
        our $AUTOLOAD;
        my $method = substr $AUTOLOAD, 2 + rindex($AUTOLOAD, '::');

        my ($self, @args) = @_;

        # [a]
        (defined $$self) ?
            __PACKAGE__-&gt;wrap( $$self -&gt; $method(@args) ) :     # [a.1]
            $self;                                              # [a.2]
    }

    sub DESTROY {}
};</code></pre><p>這類別基本上是把所有純量值都包裝成物件。<code>SafeNav</code> 類別定義有 <code>AUTOLOAD</code> 這個特殊用途的函式，使其物件可接受所有方法呼叫。就算包著的值是 <code>undef</code> 方法呼叫也都不會失敗，而是會進入 <code>AUTOLOAD</code> 函式中。
</p><p>於是在 [a] 處就可進行核心處理：若自己包著的值不是 <code>undef</code>，就對其呼叫原方法（[a.1] 處）。倘若自己包著的值已經是 <code>undef</code> 了，那繼續躺平做自己(?)就可以了（[a.2] 處）。
</p><p>多虧有 <code>AUTOLOAD</code> 機制，原連環呼叫 <code>-&gt;a()-&gt;b()-&gt;c()</code> 的部份是原樣保留著的。在此並列、比較一下：
</p><pre><code>$res = $o -&gt;a()-&gt;b()-&gt;c();
$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap();
</code></pre><p>前後的 <code>wrap()</code> 與 <code>unwrap()</code> 算是明確界定了 <code>SafeNav</code> 類別在此式中的作用範圍。過了 <code>unwrap()</code> 之後如果還繼續串著更多方法呼叫，就一定不是被包在 <code>SafeNav</code> 裡面的。
</p><p>這麼一來，會被「妥善忽略」的，就只有在碰到 <code>undef</code> 這個值的時候。若在 a、b、c 三個方法內發生了任何例外事件，程式還是能正確地被中止。並不會有太多副作用。在本文內提到的三種改寫辦法裡面，算是既通用，又不太囉唆的一種。
</p></div>
    </content>
    <category term="perl"/>
    <category term="monad"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/06/perl-safe-navigation-monad-en/?d866ed7ac2b84e1caa64462866c4e52d40705156</id>
    <link rel="alternate" href="https://gugod.org/2023/06/perl-safe-navigation-monad-en/" type="text/html"/>
    <title>[Perl] Safe-navigation Monad.</title>
    <published>2023-06-18T17:02:02+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml"><p>Recently on reddit.com/r/perl, pmz posted a question like this:
</p><blockquote>
<p>XML::Twig, get value (or not) without dying</p>
<p>Currently I do:</p>
<code><pre>
if (defined $elt-&gt;first_child('addr')-&gt;first_child('postalCode')) {
  $patient{patient_postal_code} = $elt-&gt;first_child('addr')-&gt;first_child('postalCode')-&gt;text ;
}
</pre></code>
<p>because if I don't check for "defined" and the resulting value is null , it dies.</p>
</blockquote>
<p>Link to the original post: <a href="https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/">https://www.reddit.com/r/perl/comments/1492sc1/xmltwig_get_value_or_not_without_dying/</a>
</p><p>While on one hand the question is about how to use XML::Twig, on the other hand the obvious inconvenience here is when <code>first_child('addr')</code> returns <code>undef</code>, which means there are no <code>&lt;addr&gt;</code> element underneath, the following call of <code>first_child('postalCode')</code> would make the programm die. Generally speaking: in a chain of calls we expect objects to be present in all positions, but sometimes there are <code>undef</code>. Given that, is there a way to avoid the program from dying and let the entire call chain return <code>undef</code> if <code>undef</code> is encountered in the calling chain ?
</p><p>To formalize the question a bit more generically: assume a class with instance methods <code>a()</code>, <code>b()</code>, and <code>c()</code>. These methods may return an instance of same class, or ocassionally, <code>undef</code>. Consider the following chain of calls originally from <code>$o</code>:
</p><pre><code>$res = $o-&gt;a()-&gt;b()-&gt;c();
</code></pre><p>In case any of <code>a()</code>, <code>b()</code>, or <code>c()</code> returns <code>undef</code>, the program dies with messages like this:
</p><pre><code>Can't call method "c" on an undefined value
</code></pre><p>Which suggests <code>b()</code> returns <code>undef</code> and since <code>undef</code> is not an object, we cannot call methods on it.
</p><p>Now, could we rewrite the same program to prevent the abovementioned error from happening, while making <code>$res</code> be <code>undef</code> if any of <code>a()</code>, <code>b()</code>, <code>c()</code> returns <code>undef</code>, or otherwise, the return value of <code>c()</code> ?
</p><p>In some other programming languages, such purpose could be satisfied by using the safe-navigation operator, such as <code>?.</code> in javascript or kotlin:
</p><pre><code>res = o.a()?.b()?.c();
</code></pre><p>Or in raku, <a href="https://docs.raku.org/language/operators#methodop_.%3F"><code>.?</code></a>
</p><pre><code>$res = $o.a().?b().?c();
</code></pre><p>However, we haven't seen anything similar up until perl 5.38 just yet.
</p><p>A rather intuitive way to rewrite would be something like this:
</p><pre><code>$res_a = $o-&gt;a();
$res_b = $res_a &amp;&amp; $res_a-&gt;b();
$res   = $res_b &amp;&amp; $res_b-&gt;c();
</code></pre><p>However, besides making the program much longer and less easier to grasp, the rewrite is not generic. It'll be different for similar statements with different method names. Not a good strategy.
</p><p>Meanwhile, here's a super simple and generic way:
</p><pre><code>$res = eval { $o-&gt;a()-&gt;b()-&gt;c() };
</code></pre><p>However, with the powerful side-effect of <code>eval</code>, all exceptions would be ignored while we are only interested in ignoring undefined values. That is a lot more than what we want. Even though it looks simple, it is probably not applicable.
</p><p>Here is a solution with Monad design pattern.
</p><p>The rewritten version looks like this:
</p><pre><code>$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap();
</code></pre><p>The <code>SafeNav</code> is defined as the folowing.
</p><pre><code>use v5.36;
package SafeNav {
    sub wrap ($class, $o) { bless \$o, $class }
    sub unwrap ($self)    { $$self            }

    sub AUTOLOAD {
        our $AUTOLOAD;
        my $method = substr $AUTOLOAD, 2 + rindex($AUTOLOAD, '::');

        my ($self, @args) = @_;

        # [a]
        (defined $$self) ?
            __PACKAGE__-&gt;wrap( $$self -&gt; $method(@args) ) :     # [a.1]
            $self;                                              # [a.2]
    }

    sub DESTROY {}
};</code></pre><p><code>SafeNav</code> is a class that wraps all scalar values and equips with <code>AUTOLOAD</code> for responding to all method calls. 
</p><p>Inside <code>AUTOLOAD</code> there is the core part of our logic in [a]: If we are not wrapping an <code>undef</code> value, we call the original method on it, then re-wrap the return value ([a.1]). Or if we are wrapping an <code>undef</code>, we ignore the method call and just lay down and keep being ourselves ([a.2]).
</p><p>Thanks to the mechanism of <code>AUTOLOAD</code>, the original form of <code>-&gt;a()-&gt;b()-&gt;c()</code> is kept exactly the same after the rewrite. Let's put both versions side-by-side for a quick comparison:
</p><pre><code>$res = $o -&gt;a()-&gt;b()-&gt;c();
$res = SafeNav-&gt;wrap($o) -&gt;a()-&gt;b()-&gt;c() -&gt;unwrap();
</code></pre><p>The <code>wrap()</code> at the front, together with <code>unwrap()</code> at the back, form a clear boundary in which <code>SafeNav</code> is effective. Method calls after <code>unwrap()</code> are not not guarded by <code>SafeNav</code>.
</p><p>With that, we properly ignore <code>undef</code> values, nothing more. If other kinds of exceptions are thrown from method a, b, c, the program would correctly abort. In the 3 proposed ways to rewrite the program in this article, the <code>SafeNav</code> monad is both generic and not adding too much verbosity to the original program.
</p></div>
    </content>
    <category term="perl"/>
    <category term="monad"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/05/perl-cpan-toolchain-lyon-amendment/?c475b14fbd6acd54ad91e5877787666e210a1ce9</id>
    <link rel="alternate" href="https://gugod.org/2023/05/perl-cpan-toolchain-lyon-amendment/" type="text/html"/>
    <title>[Perl] Toolchain 方面對於 perl 版本的要求</title>
    <published>2023-05-06T14:33:09+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>最近開始看到 <a href="https://perltoolchainsummit.org/pts2023/">Perl Toolchain Summit</a> 的結果了。稍微讀了一下，以此篇文章綜合摘要一下今年在 Perl Toolchain 那裡的幾項決定（Lyon Amendment）：
</p>
        <ul>
          <li>原則上 toolchain 內的軟體 (註1) 會開始追上 (註2)「十年前」的 perl 版本。(註3)
</li>
          <li>唯 2023 年例外，爲了提供給 RedHat v7 終活服務(?)而定爲 5.16。
</li>
          <li>明年 (2024) 定爲 5.20、後年 (2025) 定爲 5.22... （註4)
</li>
        </ul>
        <p>如果有經常性在升級 perl 的話應該是不會因此受到甚麼影響。主要會被影響到的應該是一些因故無法升級的老系統，最糟有可能會變成不能使用 cpan 指令來安裝模組、或是有某些重要的模組在某版之後變成無法編譯、要使用的話就必須固定使用某個舊版。在老系統上安裝新模組的需求一般來說通常倒是安全性更新。考慮到作業系統本身也需要被更新，讓 Perl / CPAN 相關工具以類似作業系統更新的步調去「與時俱進」似乎還算是合理的。
</p>
        <p>註：
</p>
        <ol>
          <li>主要是與 CPAN 生態系相關的各項工具與模組。包括模組的製作、測試、釋出、CPAN 伺服器端用的軟體等等。
</li>
          <li>原文用 "track" 這個字。這裡應該是指「如果在老於十年的 perl 環境內跑出錯誤也不再修理」的意思。
</li>
          <li>2013 年釋出的穩定版爲 5.18。
</li>
          <li>perl5 穩定版版號是每年往上加 2，並必定爲偶數。類似 Linux 的慣例。
</li>
        </ol>
        <p>參考：
</p>
        <ol>
          <li><a href="https://rjbs.cloud/blog/2023/05/pts-2023-lyon-amendment-2-5/">PTS 2023: The Lyon Amendment (minimum perl) (2/5) by rjbs</a>
</li>
          <li><a href="https://github.com/Perl-Toolchain-Gang/toolchain-site/blob/master/lyon-amendment.md">lyon-amendment.md</a>
</li>
        </ol>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
    <category term="toolchain"/>
    <category term="lyon"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/04/perl-cpan-install-dbd-mysql-with-miariadb-config/?43ad1427f9493d6e3fe635fd83e80cc9c5eb3500</id>
    <link rel="alternate" href="https://gugod.org/2023/04/perl-cpan-install-dbd-mysql-with-miariadb-config/" type="text/html"/>
    <title>[CPAN] 如何在安裝 DBD::mysql 時使其使用 MariaDB 的編譯設定</title>
    <published>2023-04-29T09:22:06+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>簡單筆記一下。以 Debian 爲例。
</p>
        <p>在安裝 <code>DBD::mysql</code> 時需要 <code>mysql_config</code> 這個指令，但如果要使用 MariaDB Client 而不能安裝 MySQL Client 時，也可以讓 <code>DBD::mysql</code> 去使用 <code>mariadb_config</code>，使其改與 libmariadb 連結。由於 MariaDB Client 也可以用來與 MySQL Server 溝通，在不想額外加入 mysql 套件的時候也可以使用這招來省點事。
</p>
        <p>首先需要裝好開發與編譯用的函式庫：
</p>
        <pre>
          <code>sudo apt-get install libmariadb-dev
</code>
        </pre>
        <p>然後是在安裝 <code>DBD::mysql</code> 時，透過指定環境變數的方式，讓其在編譯過程去使用 MariaDB 的編譯設定：
</p>
        <p>以 cpm 指令來裝
</p>
        <pre>
          <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpm install -g DBD::mysql
</code>
        </pre>
        <p>以 cpanm 指令來裝
</p>
        <pre>
          <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpanm DBD::mysql
</code>
        </pre>
        <p>以 cpan 指令來裝
</p>
        <pre>
          <code>DBD_MYSQL_CONFIG=/usr/bin/mariadb_config cpan -i DBD::mysql
</code>
        </pre>
        <p>以上。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
    <category term="DBD::mysql"/>
    <category term="MariaDB"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/03/perlx-scopefunction-0.03/?fe3ad324349663bbc5baa702ba551ac6d375c060</id>
    <link rel="alternate" href="https://gugod.org/2023/03/perlx-scopefunction-0.03/" type="text/html"/>
    <title>PerlX::ScopeFunction 0.03 釋出</title>
    <published>2023-03-17T09:41:28+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://metacpan.org/release/GUGOD/PerlX-ScopeFunction-0.03">https://metacpan.org/release/GUGOD/PerlX-ScopeFunction-0.03</a>
</p>
        <p>好幾年前我擅自開始把 PerlX:: 這個 namespace 當成是「Perl 語言的延伸」的
意義在使用，並且做了一些有的沒的新語法。最近這星期做了 PerlX::ScopeFunction。
</p>
        <p>這個模組提供兩個新的語法關鍵字: let 與 with。
</p>
        <p>先看範例，就能大致上掌握這兩個關鍵字的用法：
</p>
        <pre>
          <code>use v5.36;
use List::Util qw( sum0 );
use List::MoreUtils qw( part minmax );
use PerlX::ScopeFunction qw(let with);

my @input = (3,1,3,3,7);

let ( ($min,$max) = minmax(@input); $mean = sum0(@input)/@input ) {
    say "$min &lt;= $mean &lt;= $max";
}

with ( part { $_ % 2 } @input ) {
    my ($evens, $odds) = @_;
    say "There are " . scalar(@$evens) . " even numbers: " . join(" ", @$evens);
    say "There are " . scalar(@$odds) .  " odd numbers: " . join(" ", @$odds);
}
</code>
        </pre>
        <p>這兩個關鍵字提供了一種可以將幾個指定變數的語義範圍縮限起來的方式。前述範
例中 let 語句所造出的 $min、$max、$mean 三個變數的語義範圍是在後方的區塊
之內。with 語句則是能將一個算式取值，並把結果裝入 @_ ，使其能在後方的區塊內使
用。
</p>
        <p>這兩種語法結構都是從其他語言借過來的，在 Perl5 目前的語法中，最類似的是
sub closure 與 <code>do</code>：
</p>
        <pre>
          <code>sub {
    my ($evens, $odds) = @_;

    ...
}-&gt;(part { $_ % 2 } @input);


do {
    my ($min,$max) = minmax(@input);
    my $mean = sum0(@input)/@input;

   ...
};
</code>
        </pre>
        <p>而 PerlX::ScopeFunction 所做的就是提供一些新關鍵字，讓這種特殊片語寫起來
更加明瞭一些，也利於解讀。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
  </entry>
  <entry>
    <id>https://gugod.org/2023/01/perl-howto-list-upgradable-cpan-modules/?060b346b1b8b912642327b353d759f468bb27862</id>
    <link rel="alternate" href="https://gugod.org/2023/01/perl-howto-list-upgradable-cpan-modules/" type="text/html"/>
    <title>[Perl] 如何列出可升級的 CPAN 模組</title>
    <published>2023-01-05T10:23:09+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>一陣子之前看到的。 <a href="https://metacpan.org/dist/cpan-outdated">cpan-outdated</a> 這個指令，能列出所有可升級的模組。
</p>
        <p>它的輸出格式看來是 CPAN Mirror 底下的路徑。可以直接餵給 cpanm 去安裝。
</p>
        <pre>
          <code># cpan-outdated | head
P/PL/PLICEASE/Alien-Build-2.76.tar.gz
P/PL/PLICEASE/Alien-Libxml2-0.19.tar.gz
T/TO/TOKUHIROM/Amon2-6.16.tar.gz
R/RJ/RJBS/App-Cmd-0.335.tar.gz
O/OA/OALDERS/App-perlimports-0.000049.tar.gz
R/RJ/RJBS/App-Uni-9.006.tar.gz
P/PJ/PJACKLAM/bignum-0.66.tar.gz
L/LE/LEEJO/CGI-4.55.tar.gz
G/GA/GARU/Clone-0.46.tar.gz
P/PM/PMQS/Compress-Raw-Bzip2-2.201.tar.gz</code>
        </pre>
        <p>此外既有的 <code>cpan</code> 指令也能做到類似的事：執行 <code>cpan -O</code> 後，會列出各模組的目前版號以及最新版的版號。
</p>
        <pre>
          <code># cpan -O | head -15
Reading '/home/gugod/.cpan/Metadata'
  Database was generated on Thu, 05 Jan 2023 00:54:02 GMT
Module Name                                Local    CPAN
-------------------------------------------------------------------------
CPAN: Module::CoreList loaded ok (v5.20220520)
Acme::CPANAuthors::Austrian               1.1318  1.1318
Alien::Base                               2.5100  2.7600
Alien::Base::PkgConfig                    2.5100  2.7600
Alien::Base::Wrapper                      2.5100  2.7600
Alien::Build                              2.5100  2.7600
Alien::Build::CommandSequence             2.5100  2.7600
Alien::Build::Interpolate                 2.5100  2.7600
Alien::Build::Interpolate::Default        2.5100  2.7600
Alien::Build::Log                         2.5100  2.7600
Alien::Build::Log::Abbreviate             2.5100  2.7600</code>
        </pre>
        <p>但看來 <code>cpan -O</code> 列出的是 package 而 <code>cpan-outdated</code> 列出的是 distribution。
不過也可執行 <code>cpan-outdated -p</code>，讓它改列 package 名。
</p>
        <p>如果只是要無條件全部升到最新版的話，可以執行 <code>cpan -U</code> 或是 <code>cpan-outdated | cpanm</code>。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
    <category term="howto"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/11/perl-the-maintenance-of-date-holidays-tw-module/?c9ba407cdcdc4941e38a39f7f295b2d14291926a</id>
    <link rel="alternate" href="https://gugod.org/2022/11/perl-the-maintenance-of-date-holidays-tw-module/" type="text/html"/>
    <title>[Perl] Date::Holidays::TW 模組的製作與維護</title>
    <published>2022-11-27T14:09:43+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>幾年之前我開始把例假日的列舉做成模組、發佈到 CPAN 上面去。也就是名爲 <a href="https://metacpan.org/dist/Date-Holidays-TW">Date::Holidays::TW</a> 這個模組。這個模組基本上是帶有簡單 API 的資料集，能讓人查詢某年某月某日是否爲國定假日。所參考的資料來源有兩項：
</p>
        <p>一是行政院人事行政總處的「政府行政機關辦公日曆」，也就是在這個網址裡可以找到的某個頁面： <a href="https://www.dgpa.gov.tw/informationlist?uid=30">https://www.dgpa.gov.tw/informationlist?uid=30</a>
</p>
        <p>二是在政府開放資料平台上所找到、名爲「中華民國政府行政機關辦公日曆表」的這個資料集： <a href="https://data.gov.tw/dataset/14718">https://data.gov.tw/dataset/14718</a> 。這資料集的格式是 CSV 格式，因此主要是以此做爲資料源，再以辦公日曆來對答案。
</p>
        <p>而維護這模組主要的難處在於中華民國政府所定義的假日並不容易以計算的方式得知。因此無法製作單一一套演算法來一勞永逸。必須每年花點時間將資料匯入。而這之所以不容易計算，乃是因爲其規則有部分曖昧成分。
</p>
        <p>以下將<a href="https://www.dgpa.gov.tw/information?uid=41&amp;pid=11014">中華民國一百一十二年政府行政機關辦公日曆表</a>所節錄的放假與補假規則稍微摘要後列出：
</p>
        <ul>
          <li>a. 紀念日及節日之放假日逢例假日應予補假。例假日為星期六者於前一個上班日補假，為星期日者於次一個上班日補假。但農曆除夕及春節放假日逢例假日，均於次一個上班日補假。
</li>
          <li>b. 下列紀念日及節日放假
<ul><li>中華民國開國紀念日（一月一日）
</li><li>和平紀念日（二月二十八日）
</li><li>國慶日（十月十日）
</li><li>春節（農曆一月一日至一月三日）
</li><li>民族掃墓節（定於清明日）
</li><li>端午節（農曆五月五日）
</li><li>中秋節（農曆八月十五日）
</li><li>農曆除夕（農曆十二月之末日）
</li><li>原住民族歲時祭儀：各該原住民族放假日期，由原住民族委員會參酌各該原住民族習俗公告，並刊登政府公報。
</li><li>兒童節（四月四日）
</li></ul></li>
          <li>c. 紀念日及節日之放假日逢例假日應予補假。例假日為星期六者於前一個上班日補假，為星期日者於次一個上班日補假。但農曆除夕及春節放假日逢例假日，均於次一個上班日補假。
</li>
          <li>d. 上班日為星期一或星期五，其後一日或前一日逢星期二或星期四之紀念日及節日之放假，調整該上班日為放假日。農曆除夕前一日為上班日者，調整該上班日為放假日。
</li>
        </ul>
        <p>資料內容主要是計算出規則 b 內各項紀念日及節日所對應到的西曆日期。除了有三項爲農曆日期之外，其中「清明節」本身的計算需要將一農曆年等分，或是使用各數學家推出的近似公式解。
</p>
        <p>只是，前述假日規則之外還有個「補班」規則，也就是有幾個原本爲放假日的星期六有可能會被變爲上班日。這補班規則是列在 <a href="http://weblaw.exam.gov.tw/LawArticle.aspx?LawID=J060270000">政府機關調整上班日期處理要點</a> 的第五條：
</p>
        <blockquote>
          <p>五、因應連續假期所為之上班日調整，除特殊情形者外，以提前於前一週之星期六補行上班為原則。
</p>
        </blockquote>
        <p>也就是說，以前述規則 a、 c、 d 所做出來的補假日或放假日（通常是星期一或星期五）所形成的連續假期，會讓其之前一週的星期六有可能會變成上班日，或稱「補班日」，但也有可能不會。在規則上以「特殊情形」這個用詞留下了一些曖昧空間。
</p>
        <p>再者，由於出現上班日，使其可能會成爲假日規則中的「前一個上班日」與「次一個上班日」所指涉的目標。也就是說這幾條規則的套用次序會直接影響到結果。而任何人獨自實做出來的程式碼，對於前述幾條規則的解釋與規則套用次序的理解，都有可能不同於行政院人事行政總處的解釋。
</p>
        <p>比方說以 2023 年假日的幾個補班例子來看，若以 <a href="https://www.dgpa.gov.tw/information?uid=30&amp;pid=11070">中華民國一百一十二年政府行政機關辦公日曆表圖檔</a> 爲準，可看到 6/17 星期六爲上班日，而其次星期的 6/23 星期五爲假日，因爲 6/22 爲端午節，是假日。這部分就符合補班規則裡「提前於前一週之星期六補行上班」這半句的描述。
</p>
        <p>但若看到 3/25 星期六，也是上班日，而且其次星期一 (3/27) 到星期五 (3/31) 則全是上班日，反而是八天後的 4/3 星期一爲放假日。可知這一日的補班，並非是「於前一週之星期六」，而是「於前二週之星期六」了。可另於 2/18 及 9/23 看到類似狀況。或許這可算是某種「特殊情形」。
</p>
        <p>由 2023 年的這幾個例子來推敲，似乎可得知實際的規則如下：如果某星期一被調爲放假日，則其八天前的星期六應被調爲上班日。而若某星期五被調爲放假日，則其六天前的星期六應被調爲上班日。
</p>
        <p>但若看到一月份：1/7 星期六爲上班日，而與其對應的放假日應爲 1/27 星期五。1/27 被調整爲放假日，但其六天前的週六爲農曆除夕，本爲假日、不應該被調爲上班日。因此，或許與 1/27 對應的補班日爲 1/14 星期六。但是我的推算與行政院人事行政總處不同。顯然這就是規則中所謂的「特殊情形」了。
</p>
        <p>所以爲了求模組的正確性，就不能只依靠計算，還必須定時把公佈的假日表複製一份到 <code>Date::Holidays::TW</code> 這模組裡面去才可以。看來做月曆或手帳的業者也是無法在公佈之前自行計算出正確的補班日，每年都要手動進行這一例行公事才行。
</p>
        <p>附帶一提，似乎從沒看過這表內出現任何由原住民族委員會所定義的假日。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/09/perl-5-37-4-changes-nice-one/?be2dfb0c318438a225aba2593a92ad6e938b6cd0</id>
    <link rel="alternate" href="https://gugod.org/2022/09/perl-5-37-4-changes-nice-one/" type="text/html"/>
    <title>[Perl] 5.37.4 版中的一項很不錯的更新：編譯時期的語法錯誤訊息</title>
    <published>2022-09-21T20:55:49+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="html" xml:base="https://gugod.org">&lt;p&gt;Yves 在 perl-5.37.4 （開發版）中提供了一項很不錯的更新：
&lt;/p&gt;&lt;p&gt;以下引自： &lt;a href="https://metacpan.org/release/ETHER/perl-5.37.4/changes"&gt;https://metacpan.org/release/ETHER/perl-5.37.4/changes&lt;/a&gt;
&lt;/p&gt;&lt;blockquote&gt;&lt;p&gt;Syntax errors will no longer produce &amp;quot;phantom error messages&amp;quot;.
&lt;/p&gt;&lt;p&gt;Generally perl will continue parsing the source code even after
encountering a compile error. In many cases this is helpful, for
instance with misspelled variable names it is helpful to show as many
examples of the error as possible. But in the case of syntax errors
continuing often produces bizarre error messages, and may even cause
segmentation faults during the compile process. In this release the
compiler will halt at the first syntax error encountered. This means
that any code expecting to see the specific error messages we used to
produce will be broken. The error that is emitted will be one of the
diagnostics that used to be produced, but in some cases some messages
that used to be produced will no longer be displayed.
&lt;/p&gt;&lt;/blockquote&gt;&lt;p&gt;也就是以後在編譯時期，若發現語法錯誤，就會立刻停止。這代表：語法錯誤訊息會更加簡化。
&lt;/p&gt;&lt;p&gt;相關的公告跟 PR 在:
&lt;/p&gt;&lt;ul&gt;&lt;li&gt;&lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2022/09/msg264716.html"&gt;https://www.nntp.perl.org/group/perl.perl5.porters/2022/09/msg264716.html&lt;/a&gt;
&lt;/li&gt;&lt;li&gt;&lt;a href="https://github.com/Perl/perl5/pull/20168"&gt;https://github.com/Perl/perl5/pull/20168&lt;/a&gt;
&lt;/li&gt;&lt;/ul&gt;&lt;p&gt;寫了個就簡單的範例，用 macOS 內附的 perl5.18 、perl5.30 及用 perlbrew 裝的 perl5.37.4 來比較了一下，可以看到在語法錯誤「連續出現」時， perl5.37.4 只會報第一個錯誤，然後就停止了。範例輸出如下。
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;# bat --style numbers err.pl
   1 use strict;
   2 use warnings;
   3
   4 sub foobar {
   5     my $bar = 41
   6     my $bas = 42
   7     my $bat = 43;
   8
   9     my $bau = 44
  10     my $bav = 45;
  11
  12     say $bar;
  13 }

# /usr/bin/perl5.18 -c err.pl
syntax error at err.pl line 6, near &amp;quot;my &amp;quot;
Global symbol &amp;quot;$bas&amp;quot; requires explicit package name at err.pl line 6.
syntax error at err.pl line 10, near &amp;quot;my &amp;quot;
Global symbol &amp;quot;$bav&amp;quot; requires explicit package name at err.pl line 10.
Global symbol &amp;quot;$bar&amp;quot; requires explicit package name at err.pl line 12.
err.pl had compilation errors.

# /usr/bin/perl5.30 -c err.pl
syntax error at err.pl line 6, near &amp;quot;my &amp;quot;
Global symbol &amp;quot;$bas&amp;quot; requires explicit package name (did you forget to declare &amp;quot;my $bas&amp;quot;?) at err.pl line 6.
Can't redeclare &amp;quot;my&amp;quot; in &amp;quot;my&amp;quot; at err.pl line 9, near &amp;quot;my&amp;quot;
syntax error at err.pl line 10, near &amp;quot;my &amp;quot;
Global symbol &amp;quot;$bav&amp;quot; requires explicit package name (did you forget to declare &amp;quot;my $bav&amp;quot;?) at err.pl line 10.
Global symbol &amp;quot;$bar&amp;quot; requires explicit package name (did you forget to declare &amp;quot;my $bar&amp;quot;?) at err.pl line 12.
err.pl had compilation errors.

# perl5.37.4 -c err.pl
syntax error at err.pl line 6, near &amp;quot;my &amp;quot;
err.pl had compilation errors.&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;這個行為其實很合理，畢竟只需一字之差，就可讓一段程式碼變成非程式碼。(註1)
&lt;/p&gt;&lt;p&gt;目前為止 perl 會在看到語法錯誤時稍微多編譯一段，並試著列舉出整段程式碼幾個有可能是語法錯誤的地方。雖然這行爲有時候是有幫助的，但實際上太多錯誤訊息反而會誤導讀者，搞得讓人不太知道那一則錯誤訊息纔是癥結。
&lt;/p&gt;&lt;p&gt;各版本的 perl 提供的錯誤訊息都將第一個錯誤報在第 6 行，但實際上或許該算在第 5 行比較合理，至少以這個簡單例子來說該修正的地方就是在第 5 行行末。但畢竟，編譯器是無法自動決定「正確的」修正是該在哪裡的，程式設計師才能。
&lt;/p&gt;&lt;p&gt;如果編譯器能自動決定「正確的」修正，然後自動修正，那就表示其實這段程式碼也就是可編譯而內無語法錯誤的程式碼了。
&lt;/p&gt;&lt;hr&gt;&lt;p&gt;註1：這是個在口語用詞上一個很有意思的問題。現在所有程式語言的語法都是有完善規則的（有沒有規則書則是另外一回事）。如果有一個文字檔，裡面的內容可以讓 cc 編譯成功，一般我們就說那個檔案內容是 C 語言程式碼。但如果我們將那檔案內容改一個字符，比方說把中間某個函式尾巴的 &lt;code&gt;}&lt;/code&gt; 拿掉，使其無法被 cc 編譯成功，這時候或許我們會說那個檔案內容是「有語法錯誤的 C 語言程式碼」。可是，更加正確的說法應爲：那個檔案內容「不是 C 語言程式碼」。畢竟，如果把檔案內容拿去做個手繪語法樹出來，我們會發現最後有一條該出現的枝幹沒有出現。這就好比說，如果有人試作七言絕句一首，本應有二十八字，但創作出來的只有二十七字，我們也不會說那是「有語法錯誤的七言絕句」。當然，我們會看得出來這些內容「差一點就正確了」。或許這種容許錯誤出現的人腦內建的文字解析器，再過幾年就會被機器學習去而內嵌在某個類神經網路裡面了。
&lt;/p&gt;</content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/08/how-i-use-emacs-to-write-perl/?e01c3706b259dce2c166cefe69c5c66924e61f2e</id>
    <link rel="alternate" href="https://gugod.org/2022/08/how-i-use-emacs-to-write-perl/" type="text/html"/>
    <title>我如何設定 Emacs 來寫 Perl 程式</title>
    <published>2022-08-31T00:57:34+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>偶然讀到 <a href="https://dev.to/nicholasbhubbard/how-i-use-emacs-to-write-perl-40e6">~nicholasbhubbard</a> 的文章，發現在調整 Emacs 方面跟我最近的做法有點類似。至少主要幾項重點都一樣。
</p>
        <h2>使用 Emacs 28 內附的 cperl-mode.el
</h2>
        <p>如果系統內的 Emacs 比 28 還舊，就取 emacs.git 抓一份新的 cperl-mode.el 回來用。
</p>
        <h2>縮排以四格爲單位
</h2>
        <p>且避免讓跨行的 <code>()</code> 內容過度縮排。如果一樣是以四格爲單位，寫 lisp 時的慣例是跨行 S-exp 的內容縮到比其左括號更進一級的位置。如果左括號位置在 n，那下一行至少是 n + 4。但這條規則用來替 C / Perl 縮排的話真的會怪怪的。總合起來最少需要調整三個變數：
</p>
        <pre>
          <code>(setq cperl-indent-level 4)
(setq cperl-indent-parens-as-block t)
(setq cperl-close-paren-offset (- cperl-indent-level))</code>
        </pre>
        <p>在排程式碼之時基本上都是讓 cperl 以其自己的規則去排。但最近在試用 format-all + perltidy。perltidy 似乎對不少特定類型的程式碼沒轍，也太好調整（個人意見），雖然斷斷續續有在用，但是一直沒有調出一組夠好的參數。最近在考慮於 CI 中讓 reviewdog 去跑 perltidy，試著讓縮排風格不同的大家至少能避免在這件事上花去太多討論時間。以滿足協作這個目的而言，也有採用 editorconfig。
</p>
        <p>format-all 的好處它一律依靠外部工具來縮排，完全不依靠 Emacs 本體。而那外部工具基本上就是個社群已經熟悉的工具。若是 cperl-mode 則用 perltidy，若是 kotlin-mode 則用 ktlint。所以如果有人用 vim，也不會在縮排設定這件事情上面產生不必要的變更。
</p>
        <pre>
          <code>(use-package format-all
  :config
  (add-hook 'prog-mode-hook 'format-all-mode))</code>
        </pre>
        <h2>在專案內遊走（code navigation）
</h2>
        <p>目前覺得最好用的是 rg + dumb-jump。有嘗試使用 language server，不過還沒讓它成功過。至少依照原文件來弄的話，無法直接在我的系統中管用。猜想是跟 perlbrew 環境慣例不太合拍。但尚無仔細除錯下去的打算。rg + dumb-jump 基本上就又快又好用了。
</p>
        <p>我用 <code>use-package</code>，與 <code>dumb-jump</code> 相關的設定就這幾行：
</p>
        <pre>
          <code>(use-package dumb-jump
  :config (add-hook 'xref-backend-functions #'dumb-jump-xref-activate)
  :custom (dumb-jump-selector 'ivy))</code>
        </pre>
        <p>而目前在以檔名找檔案是使用 fzf：
</p>
        <pre>
          <code>(use-package fzf
  :bind ("C-c f" . my/fzf-current-project))</code>
        </pre>
        <h2>開終端機
</h2>
        <p>要跑指令時，目前是用 <code>vterm</code> + <code>vterm-toggle</code> 與系統上的隨便甚麼終端機混用。<code>vterm</code> 相關的設定爲這幾行：
</p>
        <pre>
          <code>(use-package vterm)
(use-package vterm-toggle
  :bind
  ("s-'" . 'vterm-toggle)
  ("H-'" . 'vterm-toggle)
  :custom (vterm-toogle-fullscreen-p t))</code>
        </pre>
        <p>綁了兩組不同的呼叫鍵給 <code>vterm-toggle</code> 函式的原因是讓 macOS 與 Linux 上都能通用。在同一把 <a href="https://gugod.org/2020/10/atreus-keyboard/">Atreus 鍵盤</a> 上，<code>s-'</code> 與 <code>H-'</code> 都是代表同樣的兩個鍵。只是同一個鍵碼在 Linux 上被抓成 <code>s-'</code>，在 macOS 上則對應到 <code>H-'</code>。
</p>
        <h2>結論
</h2>
        <p>跟許多人一樣，我有點用不慣那種會主動在畫面上提供一大堆提示的編輯器 / IDE。我覺得那很讓人分心，如果不小心點到，還得想辦法恢復原狀。因此在 Emacs 的設定方面，一向都也是維持精簡。長年下來這套設定大致上很管用。雖然不見得能讓電腦提供最大程度的協助，但是能夠把一些瑣瑣碎碎的小問題變不見就很有幫助了。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="emacs"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/08/cryptarithm-solver/?69e439badf9bf0ee9ca9fa02c5789b2ebdf1094c</id>
    <link rel="alternate" href="https://gugod.org/2022/08/cryptarithm-solver/" type="text/html"/>
    <title>數謎解謎器</title>
    <published>2022-08-23T10:35:28+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>數謎 (Cryptarithm) 是種算數謎題，謎面是由三個以上的英文單字所寫成的一個算式，其中每個字母都對應到一個自零至九之間的數目字。通常以直式寫出，例如這個經典範例：
</p>
        <pre>
          <code>  SEND
+ MORE
------
 MONEY
</code>
        </pre>
        <p>解謎者需要推敲出每個字母所對應的數目字，使算式成立。一個比較簡單的範例是：
</p>
        <pre>
          <code>  SO
+ SO
----
 TOO
</code>
        </pre>
        <p>應該不難看出有 S = 5, T = 1, O = 0 這組解。而大部分數謎都是透過讓字母的重複出現，而設計成只有一組解。
</p>
        <p>如果有個謎面是 AB + CD = EF，每個字母都只用過一次，那就隨意令 AB=12 且 C=3，馬上就可讓謎面簡化成 12 + 3D = 4F 從而得到 D=5 且 F=7。也就是 12 + 35 = 47 這組解。而且再將前面兩個數字對調，成 35 + 12 = 47，又是另一組解。
</p>
        <p>也就是說如果重複字母很少，讓自由度太高，反而會使題目變得過於簡單。
</p>
        <p>要手動解這種謎題，可先試著找出明顯的部分解答，將謎面簡化。以 <code>SEND + MORE = MONEY</code> 爲例，慣例上可排除 S=0 與 M=0，因爲數字首位不會是零（不過也有允許首位爲零的玩法）。此外，很明顯的部分解答是 M = 1：因爲兩個相異的個位數字相加，最大可得 17 (= 9 + 8)，就算再加上進位，也只會得到 18。也就是說 M 只有可能是 1 。因此可得到 <code>SEND + 1ORE = 1ONEY</code> 這個稍微簡化一些些的謎面。同時，既然 M 對應到 1，那表示其他所有字母都不可能是 1。
</p>
        <p>下一步或許是考慮 <code>S + 1 + 進位 = 1O</code>。個位數字中加了 1 就會進位的只有 9。再考慮進位可能爲 1 或 0，則 S 只可能是 9 或 8。在此出現條件分歧，可在假設 S=9 的前提之下，繼續找出其他字母對應。
</p>
        <p>也就是這個謎題基本上是個搜尋問題。在排除掉一些明顯不對的選項之後，解謎者必須逐個嘗試。配合運算規則所帶來的限制，將衆多選項一一排除，最後無法被排除而留下來的，就是解答了。
</p>
        <p>這種謎題是個很適合用來以程式做搜尋演算法的題目。搜尋範圍就是謎面中用到的所有字母所對應到的數目字之組合與排列。
</p>
        <p>對此，我想了個遞迴解：
</p>
        <pre>
          <code>sub decryptarithm (
    $cryptExpr,
    $letters         = [ distinctLetters $cryptExpr ],
    $isNonZeroLetter = +{ map { $_ =&gt; true } firstLetters $cryptExpr },
    $digitFromLetter = +{},
    $digitAssigned   = +{},
) {
    my $unboundLetter = first { !exists $digitFromLetter-&gt;{$_} } @$letters;

    # (1)
    unless ( defined($unboundLetter) ) {
        my $plainExpr = plaintextfy( $cryptExpr, $digitFromLetter );
        my $evalExpr  = $plainExpr =~ s/=/==/gr;

        # (2)
        return eval( $evalExpr ) ? $plainExpr : ();
    }

    # (3)
    my @possibleDigits = grep { not $digitAssigned-&gt;{$_} } ( ( $isNonZeroLetter-&gt;{$unboundLetter} ? 1 : 0 ) .. 9 );

    map {
        decryptarithm(
            $cryptExpr, $letters, $isNonZeroLetter,
            +{ %$digitFromLetter, $unboundLetter, $_ },
            +{ %$digitAssigned,   $_,             true },
        )
    } @possibleDigits;
}</code>
        </pre>
        <p>其中 <code>$cryptExpr</code> 就是謎面，以字串形式保存，如 <code>"SEND + MORE = MONEY"</code>。
</p>
        <p>在 (1) 處先處理終端條件。當 <code>$unboundLetter</code> 爲未定義的時候，也就是所有字母都已經有所對應的時候。這時就是依照 <code>$digitFromLetter</code> 這個對應表，把 <code>$cryptExpr</code> 明文化，得到 <code>$plainExpr</code>，並在 (2) 處，則是明文版本做出來後，簡單以 <code>eval</code> 來判別算式成立與否，如果成立，表示 <code>$plainExpr</code> 是一組解，得傳回，如果不成立，則傳回空的串列。
</p>
        <p>在 (3) 處，表示在 <code>$unboundLetter</code> 變數中所存的字母是還沒有與任何數字對應的，此時需列舉出能與這個字母對應的所有數目字，逐一遞迴嘗試。
</p>
        <p>這基本上就是個暴力搜尋的過程，除了通過 <code>$isNonZeroLetter</code> 來排除 0 之外，沒有寫入任何其他排除搜尋路徑的算式。是個很耗時間演算法。如果要做其他種類的排除，就必須先知道 <code>$cryptExpr</code> 內容是做加減乘除的那一項，再依照運算規則推敲出幾種排除規則。想來是需要不少算式才能描述得清楚。
</p>
        <p>這個解謎函式會找出謎面 <code>$cryptExpr</code> 的所有解答。若要讓它找第一組解後就停，那把最末的 <code>map</code> 改成 <code>first</code> 應該就可以了。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/08/perl-one-common-mistake-of-writing-regex/?4977faf2095430d6a72fa35a3bef973e23821a39</id>
    <link rel="alternate" href="https://gugod.org/2022/08/perl-one-common-mistake-of-writing-regex/" type="text/html"/>
    <title>[Perl] 一個常見的正規表示式的錯誤寫法</title>
    <published>2022-08-18T00:10:55+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>在不同的職場裡面都已經看過好幾次了。總是會有人用正規表示式：
</p>
        <pre>
          <code>$s =~ /\Afoo|bar\z/
</code>
        </pre>
        <p>... 來意圖檢查 <code>$s</code> 是否為 <code>"foo"</code> 或 <code>"bar"</code>。
</p>
        <p>但是這正規表示式能比對到字串不只兩個，而是無限多個。
</p>
        <p>正規表示式 <code>\Afoo|bar\z</code> 代表的是「所有以 foo 開頭的字串」與「所有以 bar 結尾的字串」兩集合的交集。而不是 {"foo","bar"} 這個只有兩個字串的集合。
</p>
        <p>要滿足原意圖，必須補上小括號，但不要把 <code>\A</code> 與 <code>\z</code> 括入：
</p>
        <pre>
          <code>$s =~ /\A(foo|bar)\z/
</code>
        </pre>
        <p>一般來說我認為，若用了 <code>|</code> ，就要同時加上小括號來明確區分出範圍，不然很容易造成誤讀。如果是明確寫成：
</p>
        <pre>
          <code>$s =~ /(\Afoo|bar\z)/
</code>
        </pre>
        <p>也可真正顯示出作者意圖真的就是要測試 <code>$s</code> 是否是「以 foo 開頭的字串」或是「以 bar 結尾的字串」。
</p>
        <p>附帶一提，以測試 <code>$s</code> 是否等於某些特定值來說，改用 <code>eq</code> 加上 <code>any</code> 來寫或許更能正確地彰顯出作者意圖。
</p>
        <p>看是要用 <code>List::Util</code> 的 <code>any</code>:
</p>
        <pre>
          <code>use List::Util qw(any);

any { $s eq $_ } qw(foo bar)
</code>
        </pre>
        <p>或是 any Junction:
</p>
        <pre>
          <code>use Quantum::Superpositions qw(any);

$s eq any( qw(foo bar) )
</code>
        </pre>
        <p>都是不錯的，也不太容易不小心寫錯。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/07/perl-grammar-compilation-with-regex/?9870afce56b13f391aeddc4f79f6b866349ac200</id>
    <link rel="alternate" href="https://gugod.org/2022/07/perl-grammar-compilation-with-regex/" type="text/html"/>
    <title>[Perl] 以正規表示式所定義的文法規則來做編譯器</title>
    <published>2022-07-20T00:36:46+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="html" xml:base="https://gugod.org">&lt;p&gt;在前文〈&lt;a href="https://gugod.org/2022/07/perl-grammar-with-regex/"&gt;[Perl] 以正規表示式來定義文法規則&lt;/a&gt;〉文中所定義的 &lt;code&gt;$JSON_GRAMMAR&lt;/code&gt; 是一個能完整地比對 JSON 文件的正規表示式，並且在其中透過了類似 BNF 的語法，以 perl 正規表示式引擎本身的處理能力來完整地是做出了一個遞迴下降解析器。
&lt;/p&gt;&lt;p&gt;但這個解析器只能做到一件事：去辨別一個字串是否看起來像是一份 JSON 文件，畢竟它就是個正規表示式。也就是說，雖然在其中定義出了各式各樣的 token 型別，但其實它的輸出只能是個布林值。如果能讓它輸出類似語法樹的資料結構，或是輸出帶有夠多輔助註解的 token 列表，都會好用得多。
&lt;/p&gt;&lt;p&gt;無奈，這兩件事都不是立刻就能做到的。甚至要直接將 &lt;code&gt;$JSON_GRAMMAR&lt;/code&gt; 拿來重複利用，都不太容易。
&lt;/p&gt;&lt;p&gt;以下是我找出的一種方式：可配合 &lt;code&gt;(?{ ... })&lt;/code&gt; 這種能內嵌程式碼的特殊語法，讓每一個 token 比對成功之後，就執行 &lt;code&gt;emit()&lt;/code&gt; 函式。並且在 &lt;code&gt;emit()&lt;/code&gt; 函式裡面記錄下各個 token 出現的位置。比對完畢之後，再整理一下，做成 token 列表。
&lt;/p&gt;&lt;p&gt;爲了解析方便，&lt;code&gt;$JSON_GRAMMAR&lt;/code&gt; 的語法規則本身也被大幅修改。大致上分成 token 與 rule 兩類。帶有 &lt;code&gt;(?{ emit(...) })&lt;/code&gt; 的就是 token，沒帶的就是 rule。目的是在取得所有 token 依照次序引出來後，能得到原本的 JSON 文件。
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;use v5.36;
use JSON        qw(encode_json);
use File::Slurp qw(read_file);
use Digest::SHA1 qw(sha1_base64 sha1_hex);

my $JSON_GRAMMAR = qr{
    (?(DEFINE)
        (?&amp;lt;JSON&amp;gt;
            (?&amp;amp;element))

        (?&amp;lt;object&amp;gt;
            ((?&amp;amp;objectBeginDelimiter) ((?&amp;amp;ws) | (?&amp;amp;members)) (?&amp;amp;objectEndDelimiter)))

        (?&amp;lt;array&amp;gt;
            ((?&amp;amp;arrayBeginDelimiter) ((?&amp;amp;ws) | (?&amp;amp;elements)) (?&amp;amp;arrayEndDelimiter)))

        (?&amp;lt;elements&amp;gt;
            ( (?&amp;amp;element) (?&amp;amp;arrayElementDelimiter) (?&amp;amp;elements) | (?&amp;amp;element) ))

        (?&amp;lt;members&amp;gt;
            ( (?&amp;amp;member) (?&amp;amp;objectMemberDelimiter) (?&amp;amp;members) | (?&amp;amp;member) ))

        (?&amp;lt;element&amp;gt;
            ( (?&amp;amp;ws) (?&amp;amp;value) (?&amp;amp;ws) ))

        (?&amp;lt;member&amp;gt;
            ( (?&amp;amp;ws) (?&amp;amp;string) (?&amp;amp;ws) (?&amp;amp;objectMemberKVDelimiter) (?&amp;amp;element) ))

        (?&amp;lt;value&amp;gt;
            ( (?&amp;amp;object) | (?&amp;amp;array) | (?&amp;amp;string) | (?&amp;amp;number) | (?&amp;amp;valueTrue) | (?&amp;amp;valueFalse) | (?&amp;amp;valueNull) ))

        (?&amp;lt;valueTrue&amp;gt; ( true )
            (?{ emit(&amp;quot;valueTrue&amp;quot;, $^N, pos())}))

        (?&amp;lt;valueFalse&amp;gt; ( false )
            (?{ emit(&amp;quot;valueFalse&amp;quot;, $^N, pos())}))

        (?&amp;lt;valueNull&amp;gt; ( null )
            (?{ emit(&amp;quot;valueNull&amp;quot;, $^N, pos())}))

        (?&amp;lt;objectBeginDelimiter&amp;gt; ( { )
            (?{ emit(&amp;quot;objectBeginDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;objectEndDelimiter&amp;gt; ( } )
            (?{ emit(&amp;quot;objectEndDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;objectMemberDelimiter&amp;gt; ( , )
            (?{ emit(&amp;quot;objectMemberDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;objectMemberKVDelimiter&amp;gt; ( : )
            (?{ emit(&amp;quot;objectMemberKVDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;objectMemberDelimiter&amp;gt; ( , )
            (?{ emit(&amp;quot;arrayElementDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;arrayBeginDelimiter&amp;gt; ( \[ )
            (?{ emit(&amp;quot;arrayBeginDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;arrayEndDelimiter&amp;gt; ( \] )
            (?{ emit(&amp;quot;arrayEndDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;arrayElementDelimiter&amp;gt; ( , )
            (?{ emit(&amp;quot;arrayElementDelimiter&amp;quot;, $^N, pos())}))

        (?&amp;lt;number&amp;gt;
            ( (?&amp;amp;integer) (?&amp;amp;fraction) (?&amp;amp;exponent) )
            (?{ emit(&amp;quot;number&amp;quot;, $^N, pos())}))

        (?&amp;lt;integer&amp;gt;
            ( (?&amp;amp;onenine) (?&amp;amp;digits) | (?&amp;amp;digit) | - (?&amp;amp;onenine) (?&amp;amp;digits) | - (?&amp;amp;digit) ))

        (?&amp;lt;digits&amp;gt;
            ( (?&amp;amp;digit)+ ))

        (?&amp;lt;fraction&amp;gt;
            ( | \. (?&amp;amp;digits) ))

        (?&amp;lt;exponent&amp;gt;
            ( | e (?&amp;amp;sign) (?&amp;amp;digits) | E (?&amp;amp;sign) (?&amp;amp;digits) ))

        (?&amp;lt;sign&amp;gt;
            ( | \+ | -))

        (?&amp;lt;digit&amp;gt;
            ( 0 | (?&amp;amp;onenine) ))

        (?&amp;lt;onenine&amp;gt;
            ([123456789]))

        (?&amp;lt;string&amp;gt;
            (&amp;quot; (?&amp;amp;characters) &amp;quot;)
            (?{ emit(&amp;quot;string&amp;quot;, $^N, pos())}))

        (?&amp;lt;characters&amp;gt;
            ( (?&amp;amp;character)* ))

        (?&amp;lt;character&amp;gt;
            ( [^\&amp;quot;\\] | \\ (?&amp;amp;escape) ))

        (?&amp;lt;escape&amp;gt;
            ( \\ | \&amp;quot; | [bfnrt/] | u (?&amp;amp;hex)(?&amp;amp;hex)(?&amp;amp;hex)(?&amp;amp;hex) ))

        (?&amp;lt;hex&amp;gt;
            ( (?&amp;amp;digit) | [abcdefABCDEF] ))

        (?&amp;lt;ws&amp;gt;
            ( ( \x{0020} | \x{000A} | \x{000D} | \x{0009} )* )
            (?{ emit(&amp;quot;ws&amp;quot;, $^N, pos())}) )
    )
}x;

my %captured;

sub emit ( $token, $content, $endPos ) {
    my $beginPos = $endPos - length($content);
    return if $beginPos == $endPos;
    my $old = $captured{$beginPos}{$token};

    if ( !$old || ( $endPos &amp;gt; $old-&amp;gt;[0] ) ) {
        $captured{$beginPos}{$token} = [ $endPos, $content ];
    }
}

sub linearize ($captured) {
    return [
        sort { $a-&amp;gt;[0] &amp;lt;=&amp;gt; $b-&amp;gt;[0] } map {
            my $beginPos = $_;
            my ( $token, @extra ) = keys %{ $captured-&amp;gt;{$beginPos} };
            die &amp;quot;Unexpected extra stuff&amp;quot; if (@extra);

            my ( $endPos, $content ) =
              @{ $captured-&amp;gt;{$beginPos}{$token} }[ 0, 1 ];

            [ $beginPos, $endPos, $token, $content ]
        } keys %$captured
    ];
}

my $filename = $ARGV[0] or die &amp;quot;A file name please.&amp;quot;;
my $json     = read_file( $ARGV[0] );

unless ( $json =~ m{ (?&amp;amp;JSON)  $JSON_GRAMMAR }gx ) {
    die &amp;quot;Not matched&amp;quot;;
}

my @tokenEvents =  @{ linearize( \%captured ) };
#=&amp;gt; Array[ [ beginPos, endPos, token, content ] ]
...&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;可看到 &lt;code&gt;$JSON_GRAMMAR&lt;/code&gt; 變長很多。爲求易讀，加了不少空白與縮排。希望多多少少可以讓人望文生義(笑)。
&lt;/p&gt;&lt;p&gt;其中常常出現的 &lt;code&gt;$^N&lt;/code&gt; 的這個特殊變數裝的是「前面那個括號所比對到的部分」，也就是實際上 JSON 文件中各個 token 的內容。而 &lt;code&gt;pos()&lt;/code&gt; 則是「目前正規表示式引擎的遊標位置」，也就「前面那個括號所比對到的部分的最後一個字符的位置」。
&lt;/p&gt;&lt;p&gt;最後做得的 &lt;code&gt;@tokenEvents&lt;/code&gt; 則是一個陣列，其內容是依照位置由前到後排序好的 token 列表。每個 token 之間不重疊。
&lt;/p&gt;&lt;p&gt;這個 &lt;code&gt;@tokenEvents&lt;/code&gt; 的製作過程之所以不那麼容易的另一個原因，是 &lt;code&gt;(?{ ... })&lt;/code&gt; 內程式碼的呼叫頻率。由於正規表示式引擎在執行過程中一定會進行回溯，對應到同一個 token 的 &lt;code&gt;emit()&lt;/code&gt; 其實會被呼叫好幾次。對於每個 token 而言，其 &lt;code&gt;emit()&lt;/code&gt; 的最後一次呼叫，才代表了解析完畢的最終結果。所以必須要先在 &lt;code&gt;emit()&lt;/code&gt; 函式內把每個位置出現的 token 全部記錄下來（記錄在 &lt;code&gt;%captured&lt;/code&gt; 變數內），等到全文解析完畢之後，再將記錄轉換成爲 &lt;code&gt;@tokenEvents&lt;/code&gt;。
&lt;/p&gt;&lt;p&gt;總之，那麼就可以拿 &lt;code&gt;@tokenEvents&lt;/code&gt; 來做一些簡單的編譯器。比方說一下這個編譯器會將 JSON 內容中的空白字符去掉，並將所有字串以 rot13 演算法處理：
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;sub rot13 ($s) {
    $s =~ tr/abcdefghijklmnopqrstuvwxyz/nopqrstuvwxyzabcdefghijklm/;
    $s =~ tr/ABCDEFGHIJKLMNOPQRSTUVWXYZ/NOPQRSTUVWXYZABCDEFGHIJKLM/;
    return $s;
}

for my $event (@tokenEvents) {
    my ( $beginPos, $endPos, $token, $content ) = @$event;

    next if $token eq &amp;quot;ws&amp;quot;;

    if ($token eq &amp;quot;string&amp;quot;) {
        $content = rot13($content);
    }

    print($content);
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;讓原本是這樣的 JSON 文件：
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{
    &amp;quot;greeting&amp;quot;: [&amp;quot;Hello World&amp;quot;]
}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;變成這樣：
&lt;/p&gt;&lt;pre&gt;&lt;code&gt;{&amp;quot;terrgvat&amp;quot;:[&amp;quot;Uryyb Jbeyq&amp;quot;]}&lt;/code&gt;&lt;/pre&gt;&lt;p&gt;而如果所要做得編譯器必須依賴語法樹，那就更加麻煩了。
&lt;/p&gt;&lt;p&gt;雖然這個做法是可行的，但其實不算太簡單，必須理解不少細節才能夠完全正確地寫出能用的編譯器。而且可能不太好延伸。但畢竟一般來說寫編譯器本來就是件複雜度比較高的題目。或許跟以 parser generator 來做編譯器的方法相比的話，複雜度其實相差不多。至少，若有某個現成的 &lt;code&gt;emit()&lt;/code&gt; 共通用，能夠用來輔助做出完整語法樹的話，就能讓編譯器的製作省點力氣。
&lt;/p&gt;&lt;hr&gt;&lt;p&gt;後記：依照 Randal Schwartz Schwartz (merlyn) 在 2012 年首次發表的 &amp;quot;&lt;a href="https://www.perlmonks.org/?node_id=995856"&gt;JSON parser as a single Perl Regex&lt;/a&gt;&amp;quot; 這篇文章內的 &lt;code&gt;$FROM_JSON&lt;/code&gt; 來看，可以透過特殊變數 &lt;code&gt;$^R&lt;/code&gt; 與正規表示式引擎的回溯是同調的這項特性來將語法樹建立出來。
&lt;/p&gt;</content>
    <category term="perl"/>
    <category term="regex"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/07/perl-grammar-with-regex/?740d4ee98715fe7b4583490674fe7b386bc83f75</id>
    <link rel="alternate" href="https://gugod.org/2022/07/perl-grammar-with-regex/" type="text/html"/>
    <title>[Perl] 以正規表示式來定義文法規則</title>
    <published>2022-07-01T00:42:29+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>Perl 語言中的正規表示式引擎在經過歷年來的擴充與改進，已經變成一種十分驚人的狀態機了，其能力遠超過教科書上所描述的「正規表示式」太多，基本上可以已經可以用來定義文法規則，並且可以直接而拿來定義一個遞歸下降解析器。
</p>
        <p>在拜讀 perlre 文件、Damian Conway 的 PPR 程式碼以及 Tom Christiansen 在 stackoverflow 上的幾篇文章之後，就想說來隨便找個語言來做個解析器看看。沒想到不太困難。
</p>
        <p>我用來學習這部分的對象是 JSON -- 是個已經很熟悉的小語言，並且在 json.org 首頁上就直接就有完整的文法規則可用。我不必費心定義，只要翻譯就可以了。
</p>
        <p>以下這個 <code>$JSON_GRAMMAR</code> 變數，裝的就是可以解析一個 JSON 文件的語法規則。除了有些不太尋常的括號之外，基本上就是與 json.org 上提供的語法規則逐一對應而已。
</p>
        <pre>
          <code class="language-perl">my $JSON_GRAMMAR = qr{
    (?(DEFINE)
        (?&lt;JSON&gt;       (?&amp;element) )
        (?&lt;object&gt;     (  { (?&amp;ws)  }   |  { (?&amp;members) }) )
        (?&lt;array&gt;      ( \[ (?&amp;ws) \]   | \[ (?&amp;elements) \] ) )
        (?&lt;elements&gt;   ( (?&amp;element) | (?&amp;element) , (?&amp;elements)) )
        (?&lt;members&gt;    ( (?&amp;member)  | (?&amp;member) , (?&amp;members) ) )
        (?&lt;element&gt;    (?&amp;ws) (?&amp;value) (?&amp;ws))
        (?&lt;member&gt;     (?&amp;ws) (?&amp;string) (?&amp;ws) : (?&amp;element) )
        (?&lt;value&gt;      ( (?&amp;object) | (?&amp;array) | (?&amp;string) | (?&amp;number) | true | false | null ) )
        (?&lt;number&gt;     (?&amp;integer) (?&amp;fraction) (?&amp;exponent) )
        (?&lt;integer&gt;    ( (?&amp;digit) | (?&amp;onenine) (?&amp;digits) | - (?&amp;digit) | - (?&amp;onenine) (?&amp;digits) ) )
        (?&lt;digits&gt;     ( (?&amp;digit) | (?&amp;digit) (?&amp;digits) ) )
        (?&lt;fraction&gt;   ( | \. (?&amp;digits) ) )
        (?&lt;exponent&gt;   ( | e (?&amp;sign) (?&amp;digits) | E (?&amp;sign) (?&amp;digits) ) )
        (?&lt;sign&gt;       ( | \+ | - ) )
        (?&lt;digit&gt;      ( 0 | (?&amp;onenine) ) )
        (?&lt;onenine&gt;    [123456789] )
        (?&lt;string&gt;     " (?&amp;characters) " )
        (?&lt;characters&gt; ( | (?&amp;character) (?&amp;characters) ) )
        (?&lt;character&gt;  ( [^\"\\] | \\ (?&amp;escape) ) )
        (?&lt;escape&gt;     ( \\ | ["bfnrt/] | u (?&amp;hex)(?&amp;hex)(?&amp;hex)(?&amp;hex) ) )
        (?&lt;hex&gt;        ( (?&amp;digit) | [abcdef] | [ABCDEF] ))
        (?&lt;ws&gt;         ( | \x{0020} (?&amp;ws) | \x{000A} (?&amp;ws) | \x{000D} (?&amp;ws) | \x{0009} (?&amp;ws) ) )
    )
}x;</code>
        </pre>
        <p>可以配合 <code>m//</code> 運算符來使用：
</p>
        <pre>
          <code class="language-perl">if ($text =~ m/ $JSON_GRAMMAR \A (?&amp;JSON) \z/x) {
    say "Valid JSON!";
} else {
    die "Invalid JSON";
}</code>
        </pre>
        <p>可以看到基本上 <code>$JSON_GRAMMAR</code> 內是一個很大的 <code>(?(DEFINE) ... )</code> 結構。這個 <code>DEFINE</code> 關鍵字，就是用來定義各條可重複利用的語法規則。而且，還可以遞迴。
</p>
        <p>每條語法規則最左邊 <code>?&lt;...&gt;</code> 這組括號內的字是這規則的名字，而右側則是這條規則所對應到的正規表示式。其中 <code>(?&amp;...)</code> 這種括號表示參照到某一條規則。可以參照到其他條規則，也可參照到目前這條規則。規則定義的次序似乎不影響結果，只要在同一個 <code>(?(DEFINE) ... )</code> 結構內就可以。
</p>
        <p>像是能對應到 JSON 中數字的名爲 <code>number</code> 的這條規則，就是定義爲： <code>integer</code> 後接 <code>fraction</code>，再接 <code>exponent</code>。
</p>
        <pre>
          <code>(?&lt;number&gt;     (?&amp;integer) (?&amp;fraction) (?&amp;exponent) )</code>
        </pre>
        <p>熟悉 yacc 的話可能會覺得這語法真是拖泥帶水，各種環綴符號真是有夠礙眼的。不過仔細閱讀一陣子之後還算可以理解。
</p>
        <p>但既然這本身是一條正規表示式，其實有不少部分可以直接使用正規表示式與生俱來的咒力(?)來處理。比方說這條規則表示：空字串或加號或減號：
</p>
        <pre>
          <code>(?&lt;sign&gt;       ( | \+ | - ) )</code>
        </pre>
        <p>其實可以簡化成：
</p>
        <pre>
          <code>(?&lt;sign&gt;       [\+\-]? )</code>
        </pre>
        <p>或是這種表示一個以上的 <code>digit</code> 重複出現的規則：
</p>
        <pre>
          <code>(?&lt;digits&gt;     ( (?&amp;digit) | (?&amp;digit) (?&amp;digits) ) )</code>
        </pre>
        <p>其實就等同於於：
</p>
        <pre>
          <code>(?&lt;digits&gt;     (?&amp;digit)+ )</code>
        </pre>
        <p>比起 Raku Grammar 或是 yacc 等能生成解析器產生器的工具而言，要習慣這個語法大概會要多花一點時間。但可以看到 Perl 的正規表示式這個語言真的完全長成另外一支語言，也完全超出了一般教科書上的規格了。而既然可以完整解析一個語言，也就可以做出編譯器，在碰到各條規則時採取相對應的行動。這方面需要在正規表示式中內嵌 Perl 程式碼，等日後再研究看看。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/06/perl-5-36-0-feature-extra-paired-delimiters/?32416dbdd9973af64cbe75273cfc7ccc3b10d38f</id>
    <link rel="alternate" href="https://gugod.org/2022/06/perl-5-36-0-feature-extra-paired-delimiters/" type="text/html"/>
    <title>Perl 5.36.0 中出現的實驗機能 `extra_paired_delimiters`</title>
    <published>2022-06-20T22:38:37+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>看來應該是伴隨 Unicode 14.0 而一併出現的機能。
</p>
        <p>所謂的 paired delimiters 指的是像 <code>()</code>、<code>[]</code>、<code>{}</code> 這種兩個一組的符號。可以配合 <code>q</code> 運算符來把字串括住，也就是所謂的「括號」。除了單引號 <code>''</code> 雙引號 <code>""</code>，透過 <code>q</code> 運算符就可以使用各式各樣的半形字符（字碼在 127 以下的）來當括號。
</p>
        <pre>
          <code>say 'It\'s a beautiful day.';
say q(It's a beautiful day.);  # 意義同上。或許比較好讀一些。

#=&gt;
# It's a beautiful day.
# It's a beautiful day.</code>
        </pre>
        <p>這種設計會出現的主要理由，是讓人便於在程式碼中定義各種內含括號的字串。普遍來說程式碼中的字串內容如果帶有符號，尤其是括號，就要以倒斜線字符 <code>\</code> 來「跳脫」。如果以單引號 <code>'</code> 來括，字串內的單引號就前就得加上跳脫字符 <code>\</code>。
</p>
        <p>自 Perl v5.36.0 起，<a href="https://perldoc.pl/5.36.0/feature#The-'extra_paired_delimiters'-feature"><code>perldoc feature</code></a> 內多了一段 <code>extra_paired_delimiters</code> 。看來是讓 <a href="https://www.unicode.org/notes/tn39/">Unicode TN39</a> 內所定義的成對刮號都可以拿來當原始碼中的字串括號使用。但是，除了一般寫文章會用到的幾組全型括號 <code>「」</code>、<code>『』</code>、<code>〖〗</code>之外，還有許多不太尋常的選項：
</p>
        <pre>
          <code>use v5.36;
use utf8;
use feature 'extra_paired_delimiters';

say q🔊電腦說：「你好，今天真是不錯。」🕪;
say q🖝怎麼這樣？🖜;
say q𝄆𝄞🎵這個字串𝄀𝄿不𝄿會自𝄀動反覆🎶𝄇 ;

#=&gt;
# 電腦說：「你好，今天真是不錯。」
# 怎麼這樣？
# 𝄞🎵這個字串𝄀𝄿不𝄿會自𝄀動反覆🎶</code>
        </pre>
        <p>可用來當左右括號的字符列表很長，在 <a href="https://perldoc.pl/5.36.0/feature#The-'extra_paired_delimiters'-feature">perldoc feature</a> 文件中有完整列出。
</p>
        <p>稍微翻了 <a href="https://github.com/Perl/perl5/search?q=paired+delimiters&amp;type=commits">perl5.git commit 記錄</a>，看來有許多額外追加進去，而不在 <a href="https://www.unicode.org/notes/tn39/">Unicode TN39</a> 列表內的符號。
</p>
        <p>但既然至少是包含了 Unicode TN39 這定義，可以想見未來或許會隨著 Unicode 本身的演進而演進。而這些括號字符的字碼幾乎全部都在 127 以上，也就是說如果不在源碼開頭加上 <code>use utf8;</code>，其實也是無法真正拿那些字符出來用的。
</p>
        <p>粗略想起來，我真的很少需要在程式碼中寫很大量的字串。需要內嵌大量「滿是括號」的字串的機會更是很少。理論上最有可能發生的時機大概就是要在 Perl 程式碼中內嵌帶 Vue 變數的 HTML，而其內容還是中文小說的狀況。這麼狀況下 <code>&lt;&gt;</code>, <code>""</code>, <code>''</code>, <code>{}</code>, <code>「」</code>, <code>『』</code> 說不定真的會同時出現在字串內。而讓人會想要使用 <code>🖝🖜</code> 來當括號......
</p>
        <p>總之，若能夠少寫一些跳脫用的倒斜線字符，就能讓易讀性向上提升一些，也可以減少在改字串內容時忘記要補上倒斜線的人爲疏失。雖然有點奇妙，但姑且就先記得有這一項選擇，看看有沒有那天會真的可以用上。
</p>
        <p>對於已經習慣使用輸入法來繕打各種全形括號的 CJK 使用者而言，或許更能善加利用這項機能吧。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/05/perl-5-36-0-new-features/?c98f8b88a8158b72cf02636be3b8a50cf1fe82c3</id>
    <link rel="alternate" href="https://gugod.org/2022/05/perl-5-36-0-new-features/" type="text/html"/>
    <title>Perl 5.36.0 帶來的新機能</title>
    <published>2022-06-02T00:05:20+08:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>在 2022 年 5 月釋出的 Perl 5.36.0 版中有不少舊的機能被徹底移除，但也多了不少新的機能。其中幾項令我注目的有：
</p>
        <ul>
          <li>subroutine signature
</li>
          <li>true, false, is_bool 及 builtin (實驗組)
</li>
          <li>一次抓出多個值的 for 迴圈 (實驗組)
</li>
        </ul>
        <h2>subroutine signature
</h2>
        <p>subroutine signature 在各語言中的意義都略有不同，但粗略地來說就是讓函式的參數列表成爲函式名稱的一部分。不過在 Perl 5.36.0 中尚沒有這麼先進，僅是把 <code>@_</code> 這個代表參數列表的變數給藏了起來而已：
</p>
        <p>5.36.0 前的寫法：得多寫一行把 <code>@_</code> 中各參數內容給拷貝出來：
</p>
        <pre>
          <code>sub foo {
    my ($p, $q) = @_;
    ...
}</code>
        </pre>
        <p>自 5.36.0 起，可改寫成如下。把參數直接列在函式名後面。在語法上，省去了使用 <code>@_</code> 的一步。
</p>
        <pre>
          <code>sub foo ($p, $q) {
    ...
}</code>
        </pre>
        <p>這個語法自 5.20 版開始就被加入實驗組，幾番修改，現在總算是正式成爲核心語法的一部分了。
</p>
        <p>與此同時，如果在帶了參數列表的函式本文內又使用了 <code>@_</code>，就會讓 perl 發出警告。例如：
</p>
        <pre>
          <code>use v5.36;

sub plus ($p, $q) {
    return $p + $_[1];
}

say plus(10, 1);</code>
        </pre>
        <p>輸出：
</p>
        <pre>
          <code>Use of @_ in array element with signatured subroutine is experimental at /tmp/x.pl line 4.
11</code>
        </pre>
        <p>可看到 <code>$_[1]</code> 還是等於 <code>$q</code>，也還是可以用。但在執行時則會有一行警告訊息跑出來。
</p>
        <p>此外，還有個附帶的好處：在函式呼叫處，如果參數的個數與宣告處的參數個數不同，則會產生執行時期的錯誤，並且就地停止。比方說我們故意丟三個參數給 <code>plus</code>：
</p>
        <pre>
          <code>use v5.36;

sub plus ($p, $q) {
    return $p + $q;
}

say "begin";
say plus(10, 1, 42);
say "end";</code>
        </pre>
        <p>輸出：
</p>
        <pre>
          <code>begin
Too many arguments for subroutine 'main::plus' (got 3; expected 2) at /tmp/x.pl line 8.</code>
        </pre>
        <p>可看到這程式輸出只到 <code>"begin"</code> 爲止，沒有包含 <code>plus</code> 傳回值，也沒有包含 <code>"end"</code>。
</p>
        <p>其實我覺得最好是讓它在編譯時期就中止，不過目前這樣也還算不錯。只是在重構程式時要確保沒有少改任何一處，以免到部署上線之後才發現錯誤連連。
</p>
        <h2>true, false, is_bool 及 builtin
</h2>
        <p>一直以來 Perl 語言中都沒有對應到 true 與 false 這兩個值，現在有了。在程式中明確寫下來的 <code>true</code> 與 <code>false</code>，在函式呼叫傳值的過程中，都會被好好保留著。但，這兩個關鍵字尚不是直接就建在語言內，而是要自名爲 <code>builtin</code> 的這個個新核心模組引入。除了新關鍵字之外，所有測試用運算子都會回傳 <code>true</code> 或 <code>false</code>，而要明確判別 <code>true</code>/<code>false</code> 與其他值，則必須用 <code>is_bool</code>。
</p>
        <pre>
          <code>use v5.36;
use builtin qw( true false is_bool );

my $p = (1 == 1);
say is_bool( $p ) ? "bool" : "not bool"; #=&gt; "bool"</code>
        </pre>
        <p>除了滿足新世代的「寫作習慣」之外，有特定值來代表 <code>true</code> / <code>false</code> 的好處就是能在將各變數轉換成 JSON 時，能夠清楚區分出 <code>1</code>、<code>"1"</code> 與 <code>true</code> 的不同，。
</p>
        <h2>一次抓出多個值的 for 迴圈
</h2>
        <p>這次在 <code>for</code> 迴圈的語法上加入了一次抓出多個值的新規則。讓人可以利用這種特性，使陣列內容兩兩一組或三三一組，做出簡單的資料結構。簡單的範例如下：
</p>
        <pre>
          <code>use v5.36;

for my ($x, $y, $z) (1..11) {
    say "$x $y $z";
}</code>
        </pre>
        <p>輸出：
</p>
        <pre>
          <code>for my (...) is experimental at /tmp/x.pl line 4.
1 2 3
4 5 6
7 8 9
Use of uninitialized value in concatenation (.) or string at /tmp/x.pl line 5.
10 11 </code>
        </pre>
        <p>可看到，在串列長度與迭代變數的個數不正好是倍數關係時，於最後一輪中，就會有幾個變數變成 <code>undef</code>。這設計還算合理。
</p>
        <h2>感想
</h2>
        <p>這次的新版出現了很多變更，稍微試用之後都覺得各設計還算合理。但似乎也有人覺得新語法的加入，漸漸地讓 Perl 語言失去了一些一致性，各語句之間變得越來越不像。不過多數變更都還是放在實驗組中的，起目的就是在於讓大家試用，找出癥結與痛點，加以改善，或是整組丟掉。
</p>
        <p>新的 <code>builtin</code> 核心模組的出現似乎是個不錯的方向，可把一些常用的，或不得不用的函式內部化，如果能逐漸充實到使人無需利用 CPAN 模組就能完成大部分簡單任務，那其實會是個很好的結果。
</p>
      </div>
    </content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/05/perl-5-36-0-released/?e58f8c8b03a24df4186a930741c24102598bd5c5</id>
    <link rel="alternate" href="https://gugod.org/2022/05/perl-5-36-0-released/" type="text/html"/>
    <title>Perl 5.36.0 釋出</title>
    <published>2022-05-31T00:07:31+08:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="html" xml:base="https://gugod.org">&lt;p&gt;@rjbs 發出的原消息： &lt;a href="https://www.nntp.perl.org/group/perl.perl5.porters/2022/05/msg263783.html"&gt;https://www.nntp.perl.org/group/perl.perl5.porters/2022/05/msg263783.html&lt;/a&gt;
&lt;/p&gt;&lt;p&gt;以下是全文轉貼：
&lt;/p&gt;&lt;hr&gt;&lt;pre&gt;
From: Ricardo Signes
Date: May 28, 2022 00:33
Subject: perl 5.36.0 is now available
Message ID: 630a8a3b-0890-40a3-b076-db8f091852ce@beta.fastmail.com

  “What!" cried he, in an accent of greater astonishment than beforem "your second witness is Monsieur Aramis?"
  "Doubtless! Are you not aware that we are never seen one without the others, and that we are called among the Musketeers and the Guards, at the court and in the city, Athos, Porthos, and Aramis, or the Three Inseparables?”

    -- Alexandre Dumas, "The Three Musketeers"

We are pleased to announce perl 5.36.0, the first stable release of version 36 of Perl 5.

You will soon be able to download Perl 5.36.0 from your favorite CPAN mirror or find it at:

https://metacpan.org/release/RJBS/perl-5.36.0/

SHA256 digests for this release are:
e26085af8ac396f62add8a533c3a0ea8c8497d836f0689347ac5abd7b7a4e00a  perl-5.36.0.tar.gz
0f386dccbee8e26286404b2cca144e1005be65477979beb9b1ba272d4819bcf0  perl-5.36.0.tar.xz

You can find a full list of changes in the file "perldelta.pod" located in the "pod" directory inside the release and on the web at:

https://metacpan.org/pod/release/RJBS/perl-5.36.0/pod/perldelta.pod
 &lt;https://metacpan.org/pod/release/RJBS/perl-5.36.0/pod/perldelta.pod&gt;

Perl 5.36.0 represents approximately a year of development since Perl 5.34.0 and contains approximately 250,000 lines of changes across 2,000 files from 82 authors.

Excluding auto-generated files, documentation and release tools, there were approximately 190,000 lines of changes to 1,300 .pm, .t, .c and .h files.

Perl continues to flourish into its fourth decade thanks to a vibrant community of users and developers. The following people are known to have contributed the improvements that became Perl 5.36.0:

Alyssa Ross, Andrew Fresh, Aristotle Pagaltzis, Asher Mancinelli, Atsushi Sugawara, Ben Cornett, Bernd, Biswapriyo Nath, Brad Barden, Bram, Branislav Zahradník, brian d foy, Chad Granum, Chris 'BinGOs' Williams, Christian Walde (Mithaldu), Christopher Yeleighton, Craig A. Berry, cuishuang, Curtis Poe, Dagfinn Ilmari Mannsåker, Dan Book, Daniel Laügt, Dan Jacobson, Dan Kogai, Dave Cross, Dave Lambley, David Cantrell, David Golden, David Marshall, David Mitchell, E. Choroba, Eugen Konkov, Felipe Gasper, François Perrad, Graham Knop, H.Merijn Brand, Hugo van der Sanden, Ilya Sashcheka, Ivan Panchenko, Jakub Wilk, James E Keenan, James Raspass, Karen Etheridge, Karl Williamson, Leam Hall, Leon Timmermans, Magnus Woldrich, Matthew Horsfall, Max Maischein, Michael G Schwern, Michiel Beijen, Mike Fulton, Neil Bowers, Nicholas Clark, Nicolas R, Niyas Sait, Olaf Alders, Paul Evans, Paul Marquess, Petar-Kaleychev, Pete Houston, Renee Baecker, Ricardo Signes, Richard Leach, Robert Rothenberg, Sawyer X, Scott Baker, Sergey Poznyakoff, Sergey Zhmylove, Sisyphus, Slaven Rezic, Steve Hay, Sven Kirmess, TAKAI Kousuke, Thibault Duponchelle, Todd Rinaldo, Tomasz Konojacki, Tomoyuki Sadahiro, Tony Cook, Unicode Consortium, Yves Orton, Михаил Козачков.

The list above is almost certainly incomplete as it is automatically generated from version control history. In particular, it does not include the names of the (very much appreciated) contributors who reported issues to the Perl bug tracker.

Many of the changes included in this version originated in the CPAN modules included in Perl's core. We're grateful to the entire CPAN community for helping Perl to flourish.

The next maintenance release, v5.36.1, will happen in the next few weeks or months.  The next development release, v5.37.0, will happen very, very soon.

-- 
Ricardo Signes, with Neil Bowers and Paul Evans
the perl steering council
&lt;/pre&gt;
</content>
    <category term="perl"/>
  </entry>
  <entry>
    <id>https://gugod.org/2022/03/attend-yapc-japan-online-2022/?aa3c04fc0ba4d74641d5dc666811ce8447eb7d5c</id>
    <link rel="alternate" href="https://gugod.org/2022/03/attend-yapc-japan-online-2022/" type="text/html"/>
    <title>線上研討會 YAPC::Japan::Online 2022 的參與經驗</title>
    <published>2022-03-06T19:45:09+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://yapcjapan.org/">YAPC::Japan</a> 研討會是日本這裡的 Perl 研討會的主幹，是 <a href="https://yapcasia.org/">YAPC::Asia</a> 的後繼。從名稱上看來就知道 <a href="https://japan.perlassociation.org/">JPA</a> 它們把規模縮小了。這樣其實很好，至少可以朝精緻化的方向前進。這幾年下來一年一回也是都辦得不錯。
</p>
        <p><a href="https://gugod.org/2019/02/yapc-tokyo/">前一回實體的 YAPC::Japan 研討會是 2019 年年初在東京</a>，當時我以靜態分析與與源碼修改建議機器人為主題給了一場 20 分鐘的日語演講。那之後<a href="https://yapcjapan.org/2020kyoto/">本來 2020 年三月預計是要在京都辦實體聚會的</a>，但是因為 covid19 的盛行與而在最後一刻而無期限延期，而 YAPC::Kyoto 大概就成為大家接下來最想去的 YAPC 了。
</p>
        <p>為了這回線上的 YAPC::Japan 研討會，主辦單位準備的「場地」大致上是這樣：
</p>
        <ul>
          <li>在議程前一天，觀眾會收到宅配。內容物是一箱禮物包跟一組烤全雞套餐，跟兩罐特製飲料，包括「YAPC 牌彈珠汽水」以及酒標是「perlbrew: Camel IPA」的啤酒。沒想到 <a href="https://perlbrew.pl">perlbrew</a> 真的變成酒標了。
</li>
          <li>雙軌議程，各自有 youtube 公開直播。影片網址分享到 SNS 上也無所謂，主辦單位有明確提到這一點。
</li>
          <li>Discord 文字與聲音聊天空間。在演講直播當中，觀眾們可以利用 Discord 的聲音聊天室來立刻對演講反應，或跟「隔壁」的人立刻討論。如果講者本人也有參與聲音聊天室的話則可以聽到回應，但粗估資訊延遲約有 20 秒左右。
</li>
          <li>主辦單位以 Zoom 與講者連線，取得講者的所分享的螢幕畫面與 Webcam 影像，將兩影像源安到特定模板上後，做成直播影片。這個模板部分的主要目的，是將贊助商的名字與商標放在畫面一個角落輪播。
</li>
          <li>演講議程之外，另外有「幫忙學生線上解題」，以及「Perl 川柳大會」兩個活動。參與度似乎很熱烈。這川柳大會還有獎品。主辦單位最後有挑出五名佳作，贈予「技術書１万円分」。真是不錯啊。
</li>
        </ul>
        <p>在議程中的「下課時間」是 15 分鐘為單位，比起一般實體研討會似乎略微緊湊一些。在下課時間中，直播畫面就會開始播放贊助商提供的形象廣告影片。
</p>
        <p>LINE 與 DeNA 一直都是 YAPC::Japan 及 YAPC::Asia 的重量級贊助商，所以在議程中有特定的發言時段，事前送給觀眾的禮物與烤雞應該也是主要靠他們的贊助。而另外比較令我印象深刻的是，眾多贊助商中出現了<a href="https://www.pizzahut.jp/">必勝客披薩</a>，他們有在閃電講中獲得五分鐘宣傳時段，而且講者講得還不錯，雖然單純就只是宣傳，不是與 Perl 或任何技術方面相關話題。但更妙的是，對於一部分報名者，他們提供了在指定時間送達的服務。因此在當日下午三點半前後可以在 Discord 與 Twitter 上同時看到超多人在說「Pizza 送來了」。
</p>
        <p>如果只是當觀眾的話，這樣的體驗，至少以「聽課」這個目的來說算是還不錯的。因為視線絕對不會被前面的人擋到，甚至如果漏聽了幾秒也還可以稍微倒帶回去補聽一下。但是完全沒辦法做出夠快的問答，至少在演講途中是無法模擬出「舉手問問題」的這個過程。Discord 的聲音聊天室大致上可以讓兩個人對話 N 個人聽也不會因延遲而感到怪怪的。似乎也足夠了。而且在講師講課時，聽眾也可以在 Discord 裡面討論，自由度（？）很高。
</p>
        <p>但反過來說，當講者的話，就要去習慣這所謂的給演講，其實只是自己對著自己的電腦螢幕講話，完全無法有任何方式去接受到從觀眾席傳來的任何反應。在 Zoom 畫面上，就只能看到同時連線在同一場會議中的工作人員數人。雖然一定程度上可以觀察他們的表情，但也只是聊勝於無。要在這種線上研討會給演講的話，好好地將自言自語的能力練好，似乎很重要。
</p>
        <p>「幫忙學生線上解題」的這個活動是有個出題者，出兩題不難的題目讓三位學生來解題，學生在解題的時候需要把螢幕分享在 Discord 頻道中讓觀眾看。如果觀眾看到學生卡關的話就可以提供口頭上的協助。雖然我不確定在這活動中三位學生的角色是怎麼決定出來的，但這似乎是個很有意思的群體活動。
</p>
        <p>這次我選擇給一場五分鐘長度的<a href="https://en.wikipedia.org/wiki/Lightning_talk">閃電講</a>。講題是 <a href="https://github.com/gugod/aaa-pl">aaa.pl</a>，是 <a href="https://gugod.org/2018/08/tpc-glasgow/">2018 年在 TPC::Glasgow</a> 時以英語講過一次的題目，內容基本上算是半娛樂性質。當時沒什麼練習而講得有點結巴。這次以日語來講，而且由於「場地因素」，我無法知道聽眾是否看起來能聽懂我的破日語。為了不要出糗出的太超過，事前練習了六七次，沒想到每一次都遠超過五分鐘。還好有先練習與調整，不然實際上場時鐵定是要超時了。沒想到還得到了一個獎，或許有練習真的有差了，雖然是覺得有點意外的。但從聊天室與 twitter 上的訊息看來這次演講效果應該算是不錯吧。
</p>
        <p>依照慣例：這研討會活動在 SNS 上用 #yapcjapan 作為其標籤。<a href="https://twitter.com/search?q=yapcjapan&amp;f=live">在 twitter 上搜尋 #yapcjapan</a>，就可獲得與其相關的各種訊息與事後感想。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="conference"/>
    <category term="yapcjapan"/>
  </entry>
  <entry>
    <id>https://gugod.org/2021/11/fuzzing-regexp/?b8fa243d4b818d0aeff641f79e3696bdaa317175</id>
    <link rel="alternate" href="https://gugod.org/2021/11/fuzzing-regexp/" type="text/html"/>
    <title>對正規表示式進行模糊測試</title>
    <published>2021-11-12T21:35:57+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p>拜讀了 <a href="https://blog.cloudflare.com/details-of-the-cloudflare-outage-on-july-2-2019/">Cloudflare 服務中斷報告</a>，腦海浮現了對正規表示式去進行模糊測試的想法。針對此題目，我於 <a href="https://perlcon.eu/">2019 年 Europe PerlCon</a> 研討會上給了場五分鐘的閃電講：<a href="https://hackmd.io/@gugod/BkahxPFQH#/">Fuzzing regexp (WIP)</a>。
</p>
        <p>模糊測試的過程，大致上設想如下：
</p>
        <ol>
          <li>對所指定的測試目標 r （正規表示式​）生成一測試用函式 f(x)。此函式的參數 x 為一個字串，回傳值為一個正整數，表示處理參數之字串所需要的步數。
</li>
          <li>隨機產生許多長度為 1...n 的字串 x
</li>
          <li>取所有 ( length(x), f(x) ​) ，以線性回歸判斷兩者關係是否為線性
</li>
        </ol>
        <p>雖然已經初步以 <a href="https://metacpan.org/pod/Regexp::Debugger">Regexp::Debugger</a> 完成 <a href="https://github.com/gugod/bin/blob/master/refuzz">refuzz</a>​，但尚有兩點問題待解：
</p>
        <ol>
          <li>隨機生成的字串 x 有很高的機率是不會與 r 匹配成功的，如果只生成那種很快就會匹配失敗的字串，f(x) 就會一直很小​。必須仔細依 r 的內容來撰寫字串產生器才能進行較有效率的測試。
</li>
          <li>Regexp::Debugger 所實做的是沒有經過任何最佳化過的 DFA​ 引擎，雖然有代表性，但可能與實際上各市面上常見的引擎有點出入
</li>
        </ol>
        <p>總之是個可以來慢慢研究的主題，日後若有更新再來追加補充。
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="regexp"/>
    <category term="fuzzing"/>
  </entry>
  <entry>
    <id>https://gugod.org/2021/10/perl-making-single-binary-release-with-pp/?ef899afcbc99e6e76cc419fccb1ed9ad30a4ca83</id>
    <link rel="alternate" href="https://gugod.org/2021/10/perl-making-single-binary-release-with-pp/" type="text/html"/>
    <title>Making Single-binary Release with pp</title>
    <published>2021-10-19T21:23:58+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><code>pp</code> comes with <code>PAR::Packer</code>, which is a tool for "compiling" a bunch of modules and codes and makes a single binary.
</p>
        <p><code>perldoc pp</code> already contains a good amount of documentation one can refer to.
</p>
        <p>While it works with system perl, I found it even easier to first prepare a directory of <code>local::lib</code>, then just package that entire directory.
</p>
        <p><code>pp</code> tries its best to determine the list of dependencies of the given program in various ways but none of those are guaranteed to be 100% accurate. As matter of fact that guarantee is impossible to make. This is partially due to the fact that a running program can load modules in ways that cannot be easily determined by reading the program source code, or in a relative hidden code path that cannot be easily captured.
</p>
        <p>That is a good amount of flexibility, but definitely a pricey one. Although, arguably it is also an issue brought by the tool (<code>pp</code>, <code>perlcc</code>, <code>perl2exe</code>, etc.). I guess that is because the dynamic nature is so convenient as long as all the installation are done right. Having a tool that is able to automically complie all dependencies together was not needed that much. It has definidently needed, that is why we have those tools now, but in the last mile of their completion, lies an undecidable problem.
</p>
        <p>So we will need to manually add those missing depedencies to <code>pp</code> command, which is fine only when the list is small. Since we wish to just pack all the declared dependencies together, we don't care that much even if that's going to make the result a little bigger than it has to be. If we can have the same build script that works everywhere, it is as happy as in Christmas. (An pure metaphoric experssion. Pesonally I feel nothing spceial in Dec 25.)
</p>
        <p>Anyway...... it turns out to be much easier to decide the dependency at installation time, since that's all well-declared and tools like <code>cpm</code>, or <code>cpanm</code> already does this perfectly. If we install dependencies in a self-contained directory, we could just archive the entire directory together with the program we are packing, and that should be good to go.
</p>
        <p>Let's say we cd into the source code of <code>foo</code> and we are trying to compile the program <code>foo</code> as a binary. The executable is at <code>bin/foo</code>, while its own moulders such as <code>Foo.pm</code>, <code>Foo/Bar.pm</code> are put under the conventional directory <code>lib</code>.
</p>
        <p>Given that, this script should produce <code>foo</code> as a single binary that as if all dependencies are "statically-linked" inside:
</p>
        <pre>
          <code>#!/bin/bash

# Prepare local/ 
cpanm -L local -q --installdeps .
# or: cpm install

perlversion=$(perl -MConfig -e 'print $Config{version}')
pp -B \
    -I ./local/lib/perl5 \
    -a "./local/lib/perl5/;$perlversion/" \
    -a lib \
    -o foo \
    bin/foo</code>
        </pre>
        <p>Alas, this is almost perfect -- except modules in corelist might still be missing. They won't be inside <code>local/</code> and if they are somehow not discovered by <code>pp</code> then they'll be missing in the end result. We won't know this until we manually test the result <code>foo</code> thoroughly. Basically we should always add a bunch of <code>-M</code> flags in the build script instead of assuming <code>pp</code> would do the right thing.
</p>
        <p>For example, like so, when all of <code>Getopt::Long</code>, <code>JSON::PP</code>, and <code>Sys::Hostname</code> are required.
</p>
        <pre>
          <code>pp -B \
    -M Getopt::Long:: \
    -M JSON::PP:: \
    -M Sys::Hostname:: \
    -I local/lib/perl5 \
    -a "./local/lib/perl5/;$perlversion/" \
    -a lib \
    -o foo \
    bin/foo</code>
        </pre>
        <p>A rather tedious modification as the list of dependent modules now exists in two places in the repo. Surely there is some way to refactor this.
</p>
        <p>I've verified the following script <code>build-minicpan.sh</code> that can download the tarball of <code>CPAN::Mini</code> and build a working <code>minicpan</code> out of it:
</p>
        <pre>
          <code>#!/bin/bash
set -e

curl --silent -O https://cpan.metacpan.org/authors/id/R/RJ/RJBS/CPAN-Mini-1.111016.tar.gz

tar -xzf CPAN-Mini-1.111016.tar.gz

cd CPAN-Mini-1.111016

cpanm -n -q -L local --installdeps .

perlversion=$(perl -MConfig -e 'print $Config{version}')

pp -B \
   -M Getopt::Long:: \
   -I ./local/lib/perl5 \
   -a "./local/lib/perl5/;$perlversion/" \
   -a lib \
   -o ../minicpan \
   bin/minicpan

echo "DONE: minicpan"</code>
        </pre>
        <p>To me this seems to be an area worth exploring... I've been experimenting the automation of this in a side-project: <a href="https://github.com/gugod/pau">pau</a>, which is a collection of shell functions that can install app to their own self-contained directory and expose just the program itself. Very similar to what <a href="https://pypa.github.io/pipx/">pipx</a> does. The support of <code>pp</code> was added not long ago but still, there is no good way to figure out all the missing modules and automatically add them as <code>-M</code> arguments.
</p>
        <p>Maybe as a lazy solution, we should just <em>always</em> produce a heavy-pack that includes the whole core lib directory (usually <code>$INC[-1]</code>) regardless whether any of them are used.
</p>
        <p>Maybe.
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
    <category term="compiling"/>
  </entry>
  <entry>
    <id>https://gugod.org/2021/09/cpan-release-of-toomuchcode-0.18/?7c7a26ed4538ed3e35aa89101e3fadca6d354377</id>
    <link rel="alternate" href="https://gugod.org/2021/09/cpan-release-of-toomuchcode-0.18/" type="text/html"/>
    <title>CPAN Release of TooMuchCode 0.18</title>
    <published>2021-09-29T08:48:06+09:00</published>
    <author>
      <name>gugod</name>
    </author>
    <content type="xhtml" xml:base="https://gugod.org">
      <div xmlns="http://www.w3.org/1999/xhtml">
        <p><a href="https://metacpan.org/dist/Perl-Critic-TooMuchCode">Perl::Critic::TooMuchCode</a> is a set of policy addons that generally checks for dead code or redundant code.
</p>
        <p>It's just about a week after <a href="https://gugod.org/2021/09/cpan-release-of-toomuchcode-0.17/">the release of 0.17</a> and after asynchronously exchanged some thoughts with <a href="https://github.com/oalders">@oalders</a> and <a href="https://github.com/ferki">@ferki</a> (<a href="https://github.com/gugod/Perl-Critic-TooMuchCode/issues/25">Issue #25</a>), I decide to make a follow-up release shortly.
</p>
        <p>In version 0.17 we updated the policy ProhibitDuplicateLiteral to include a new config parameter <code>whitelist</code> to replace the old parameter <code>whitelist_number</code>. In version 0.18 they are both removed. The replacement for them is the parameter <code>allowlist</code>.
</p>
        <p>So now if we really need to write number 42 and "forty two" literally many times, we list them in <code>.perlcriticrc</code>:
</p>
        <pre>
          <code>[TooMuchCode::ProhibitDuplicateLiteral]
allowlist = "forty two" 42</code>
        </pre>
        <p>The name "allowlist" was previously suggested by <a href="https://github.com/ferki">@ferki</a> already and I amended to match existing convention of using "whitelist". Now I decide that such convention should be changed (See <a href="https://github.com/gugod/Perl-Critic-TooMuchCode/pull/28">PR #28</a>). It's a better naming choice in the sense that it direct and explicit, perhaps until the day the word "allow" lost its current meaning.
</p>
        <p>The other improvement is to address <a href="https://github.com/gugod/Perl-Critic-TooMuchCode/issues/19">Issue 18</a> (thanks to <a href="https://github.com/oalders">@oalders</a> again.), in which assignment of imported symbols to <code>@EXPORT</code> or <code>@EXPORT_OK</code> as correctly counted as using those symbol by the policy ProhibitUnusedImport.
</p>
        <p>There have not counted because it is also a correct thing to do. Considering we have three symbols in place: <code>foo</code>, <code>$bar</code>, and <code>@baz</code>, and an assignment like this:
</p>
        <pre>
          <code>my @stuff = qw(foo $bar @baz);</code>
        </pre>
        <p>Although those symbols appears in the statement literally, evaluating that statement does not depends on the evaluation of those symbols because they are all quoted inside of <code>qw()</code>. <code>@stuff</code> is evaluated to 3 strings: <code>'foo'</code>, <code>'$bar'</code>, and <code>'@baz'</code>, which has nothing to do with <code>foo</code> (bareword, perhaps a subroutine name), <code>$bar</code>, and '@baz'.
</p>
        <p>However, if the LHS array variable is either <code>@EXPORT</code> or <code>@EXPORT_OK</code>, the assignment has different meaning:
</p>
        <pre>
          <code>our @EXPORT = qw(foo $bar @baz);
our @EXPORT_OK = qw(@baz);</code>
        </pre>
        <p><code>@EXPORT</code> itself is still assigned with just 3 strings, but eventually when the current module is imported (<code>use</code>-ed or <code>require</code>-ed) by a foreign piece of code, those 3 strings refer some content in the symbol table and they might be used remotely.
</p>
        <p>Well, whether <code>foo</code> is really used remotely is probably unknown-able. It should be sufficient to just consider the case of assignments involving <code>@EXPORT</code> and <code>@EXPORT_OK</code>.
</p>
        <p>I'm guessing that there are probably more special cases yet to be discovered regarding those special variables in <a href="https://perldoc.pl/perlvar">perlvar</a>, or however famous module X defined its own sub-language for us to cope with.
</p>
      </div>
    </content>
    <category term="perl"/>
    <category term="cpan"/>
  </entry>
  <updated>2024-06-09T23:01:41+09:00</updated>
</feed>
