工具箱語言
原文由 Hillel Wayne 于 發布,訂閱此部落格
所謂的工具箱語言,就是那種不需要依賴第三方套件就能很好解決問題的程式語言。我平常用的工具箱語言是 Python 和 shell 指令稿,這些你大概都已經知道了。接下來要介紹的是一些比較冷門的選擇。
AutoHotKey
這個一定要提!AutoHotKey 基本上就是「給 GUI 用的 shell 指令稿」。它是個超棒的工具,能讓那些本身不支援程式化的應用程式變得好用許多。它只能在 Windows 上跑,不過 Mac 和 Linux 上也有類似的工具。
實用功能:
- 你可以設定只在特定程式中生效的快捷鍵,或是只有在某個全域旗標被啟用、螢幕上出現特定文字時才會生效的快捷鍵等等。
- 可以很輕鬆地取用大量基礎的 win32 功能。比方說要打開檔案選擇對話框,只要寫
f := FileSelect()就好。 - 它的 GUI 框架真的、真的非常好用。老實說,就我用過的語言來說,至少在做小東西時,它是最好的。
範例問題:
Audacity 不讓你設定滑鼠快捷鍵,所以我用 AutoHotKey 把滑鼠中鍵對應到鍵盤快捷鍵。
#HotIf WinActive("ahk_exe audacity.exe")
MButton::Send "^l" ; silence selection
#HotIf我讓輸入 ;iso 就會自動填上當天的日期。
:R:;iso::
{
Send(FormatTime(,"yyyy-MM-dd"))
}這是我用來做附帶時間戳記筆記的小工具。
; right-ctrl + d
>^d::
{
TimeString := FormatTime(,"MM/dd hh:mm tt")
t_msg := InputBox(,TimeString,"w200 h100")
if t_msg.Result = "OK" {
timestampfile := A_WorkingDir . "\Config\timestamps.txt"
FileAppend(TimeString . "`t" . t_msg.Value . "`r`n", timestampfile)
}
}其他用途:替工具箱語言啟動 REPL。輸入通關某款遊戲所需的 100 次按鍵序列(懂的人就懂)。
延伸閱讀:
J
這是一個陣列語言,就像 APL 一樣。處理陣列運算時非常強大,但只要碰到字串或結構化資料,就會讓人抓狂。我以前很常用它,但現在大多改用其他工具了,像是 Excel 和 Raku。不過在它擅長的領域,它依然非常厲害。
實用功能:
- 它極度精簡。在多數語言裡要寫好幾行的東西,在 J 裡只要幾個字元就能搞定,所以我喜歡用它來快速做一堆數學運算。
- 一級的多維陣列。
+可以把兩個數字相加、把兩個陣列逐元素相加、把一個數字加到陣列的每個元素上,或是把一個陣列加到更高維度陣列的每一列(或每一欄)。 - 有很多頂層的基本運算(primitive),專門處理特殊的數學操作,像是把一個數字分解成質因數。
範例問題:
取得一個數字的所有質因數:
q: 2520
2 2 2 3 3 5 7假設有兩個行程,各自執行一個四步驟的演算法,會有多少種可能的交錯執行方式?
ni =: !@:(+/) % */@:!
ni 4 4
70如果我想列出 1 到 3 個處理器、1 到 3 個步驟各自對應的交錯數量表格呢?
(ni@:$)"0/~ >: i. 3
1 1 1
2 6 20
6 90 1680延伸閱讀:
- J 記法作為一種思考工具
- 把 J 當成桌面計算機
- 如何解數獨(主要是附錄)
Frink
這可能是這份清單上最冷門的語言。Frink 是為了因次分析(也就是帶單位的數學)而設計的,但它也塞進了一堆開發者覺得有趣的功能——而且還真不少!它大概是我見過的程式語言裡,最接近「更好的計算機」的一個:容易上手、功能強大,又沒有 J 或 Raku 那種陌生的語法。
實用功能:
- 內建大量的單位和單位修飾詞。
calendaryear正好是 365 天,tropicalyear是 365.24 天,而half nanocentury大約是 1.6 秒。 - 日期字面量語法:
# 2000-01-01 # - # 200 BC #會得到 2199.01 年。 - 內建用來處理不確定性的區間型別。有點笨拙,但堪用。
範例問題:
如果有人在 1970 年 1 月 1 日午夜出生,那他什麼時候會滿十億秒大?
# 1970 # + 1 billion seconds
AD 2001-09-09 AM 02:46:40.000 (Sun) Central Daylight Time如果我用某個時間跑完某段距離,我的平均配速是多少?
// In miles per hour
2.5 miles / (27 minutes + 16 seconds) -> mph
5.5012224938875305623
// In meters per hour
2.5 miles / (27 minutes + 16 seconds) -> meters / hour
8853.3594132029339854
// In (minutes, seconds) per mile
1 / (4.5 miles / hour) -> [minutes/mile, seconds/mile, 0]
13, 19(6 ± 2)*(8 ± 1)是多少?
x = new interval [2, -2]
(6 + x) * (8 + x/2)
[28, 72] // range is between 28 and 72延伸閱讀:
Raku
Raku(原名 Perl 6)是一個非常奇怪的語言,充滿了各種黑魔法。它非常強大,但也非常容易搞砸。我還不太敢拿它來跑正式環境的程式。但拿來寫個人腳本和工具箱用途,它就非常驚人。
實用功能
- 你可以自己定義中綴運算子!還有後綴運算子。以及環綴運算子。
- 多到嚇人的語法糖,多到讓我有點擔心的程度。比方說,你不用寫
[1, 2],可以直接寫<1 2>。也不用寫["a", "bc"],直接寫<a bc>就好。Raku 就是 Just Knows™ 該怎麼做。 - 如果你定義了一個
MAIN函式,它的參數就會自動變成 CLI 參數。 - 基於執行期數值的多分派多重方法。把它跟
MAIN結合起來,要做小型的 CLI 工具就變得非常容易。 - 許多數學運算子都有對應的 Unicode 符號(例如用 ∈ 來表示
(elem)),這跟我的 AutoHotKey 熱字串搭配起來效果絕佳。
範例問題
產生三個隨機的 10 個字元小寫字串。
> for ^3 {say ('a'..'z').roll(10).join}
fflqymxapa
znyxehaqvo
qwqxusudqw用文法(grammars)來解析不常見的結構化資料格式(見連結)。
把一堆 SVG 的 id 複製到 inkscape 標籤裡。
use XML;
my $xml = from-xml-file("file.svg");
for $xml.elements(:NEST, :RECURSE<99>) -> $e {
with $e<id> ~~ /k\w/ {
say $_.target;
$e.set("inkscape:label", $_.target);
}
}
$xml.save()寫一個帶有幾個繁瑣選項組合的 CLI(範例)。
延伸閱讀:
Picat
這是我最新的工具箱語言,也是讓我開始思考工具箱這個概念的語言。它是邏輯程式設計、約束求解和指令式逃生艙口的強烈混合體。我一開始是把它當成「更好的約束求解器」來學的,後來卻不斷發現它的新用途。
實用功能:
- 可以對變數賦值。在邏輯語言裡這意外地非常有用。很多問題感覺幾乎很適合用邏輯程式設計來解,但總會有一小部分演算法讓我想破頭也想不出要怎麼 100% 用邏輯來表達。指令式就提供了我需要的逃生艙口。
planner模組。我超愛planner模組。它是我的好麻吉。給它一個目標和一串可能的動作,Picat 就會找到一連串能達成目標的動作。超級酷。
範例問題:
如果我以 4.5 英里/小時跑了 X 分鐘,再以 5.1 英里/小時跑了 Y 分鐘,要怎麼選 X 和 Y 才能在 38 分鐘內跑完 3.1 英里?
import cp.
[X, Y] :: 1..60, 45*X + 51*Y #= 31*60, X+Y #= 38, solve([X,Y]).
X = 13
Y = 25
yes給定一堆活動、時間限制和互斥條件,規劃出一個假期行程。
檢查一個邏輯謎題是否有多組解。檢查邏輯謎題的線索是否有多餘,或是否可以移除其中一條線索仍維持唯一解。
快速做出一個 Petri net 的可達性求解器。
延伸閱讀:
什麼造就了好的工具箱語言?
我見過的大多數好的工具箱語言都是用來做計算的。我認為用來處理效應(effects)和自動化的工具箱語言也是可行的(像 AutoHotKey 這樣),只是這個領域比較少人探索。
一個工具箱語言應該要寫起來非常、非常快。至少要比 Python 快。比較一下「十對隨機數字」怎麼寫:
# python
from random import randint
[(randint(10), randint(10)) for _ in range(10)]
# Raku
^10 .roll(2) xx 10
# J
10 2 ?@$ 10有幾個因素會促成這點:精簡的語法代表要打的字更少。大量內建功能代表不用自己寫一堆基礎的東西。從標準函式庫匯入雖然不是最理想,但還可以接受。需要另外安裝第三方套件就讓我很困擾了。Raku 在這方面做得很酷;Rakudo Star Bundle 就預先打包了一堆實用的社群套件。
如果你能用一行就搞定某件事,你就可以直接丟進 REPL 裡跑。所以你會想要一個好的 REPL。我用的大多數語言都有不錯的 REPL,不過我想我的 Lisp 和 Smalltalk 讀者們對於什麼叫「好的 REPL」肯定會有不同的看法。
理想上,語言應該要有平緩的學習曲線。Raku 雖然很複雜,但你只要學一點點就能派上用場,而 J 的學習曲線就太陡了,不太適合推薦給大多數人。不過,這點往往會跟「寫起來快」有所衝突。
我想放進工具箱的其他工具
- jq 用來處理 JSON
- JavaScript,這樣我就能透過開發者控制台去修改別人的網站
- 某種 APL,能提供 J 的好處,但又不會有我一直遇到的那些挫折
- 一個串接式程式語言(concatenative PL),如果我哪天搞清楚 CPL 到底適合解決什麼小問題的話
- 某種能讓網頁爬取和解析變得跟計算一樣簡單的東西。Requests 跟 bs4 才不是。
感謝 Saul Pwanson 提供的回饋。如果你喜歡這篇文章,歡迎訂閱我的電子報!我每週都會在那裡發表新的文章。
我為企業提供形式化方法的培訓,讓軟體開發更快、更便宜、更安全。歡迎點此了解更多。
我的新書 Logic for Programmers 現已開放搶先體驗!請點此查看。
隨機一篇部落格
留言
登入後參與討論