Lîm Tsú-thuàn [dan-0001]
Lîm Tsú-thuàn [dan-0001]
This blog majorly writes about computer science and mathematics, also is my personal public notes. Feel free to point out any good reference of topic you view on the site, I will add them into reference if proper.
1. Blog Posts [posts]
1. Blog Posts [posts]
Sage 使用:微分方程式 [sage-0002]
- December 2, 2024
- Lîm Tsú-thuàn
- https://doc.sagemath.org/html/en/tutorial/tour_algebra.html
Sage 使用:微分方程式 [sage-0002]
- December 2, 2024
- Lîm Tsú-thuàn
- https://doc.sagemath.org/html/en/tutorial/tour_algebra.html
變數依然是使用 var
函數 t = var('t')
,不過要建立依賴 t
的函數變數就需要寫
x = function('x')(t)
方程式寫成 DE = diff(x, t) + x - 1
\(= \frac {d x}{d t} + x - 1\)。解方程式要用 desolve
函數,desolve(DE, [x,t])
\(= e^{-t} (C + e^t)\)
Sage 使用:微積分 [sage-0001]
- November 22, 2024
- Lîm Tsú-thuàn
Sage 使用:微積分 [sage-0001]
- November 22, 2024
- Lîm Tsú-thuàn
首先,用 var
建立變數
x = var('x')
接著就可以按照常見的方式定義函數,比如
f = x^3
微分 (diff
函數) [#287]
- November 22, 2024
- Lîm Tsú-thuàn
微分 (diff
函數) [#287]
- November 22, 2024
- Lîm Tsú-thuàn
在 sage 中要使用 diff(f, x)
來計算微分,比如這裡 diff(f, x)
\(= 3x^2\)。當然常見的數學定義也都可以使用,例如
-
diff(e^x,x)
\(= e^x\) -
diff(sin(x),x)
\(= cos x\) -
diff(cos(x),x)
\(= -sin x\)
Warning. [#288]
- November 22, 2024
- Lîm Tsú-thuàn
Warning. [#288]
- November 22, 2024
- Lîm Tsú-thuàn
有個需要注意的小細節是 f(x) = x^3
不等於 f = x^3
,兩者的調用方式並不相同
- 第一個要用
f(1)
- 第二個要用
f(x=1)
同理,diff(f, x)
的結果也受到 f
的定義方式影響
積分 (integral
函數) [#289]
- November 22, 2024
- Lîm Tsú-thuàn
積分 (integral
函數) [#289]
- November 22, 2024
- Lîm Tsú-thuàn
-
integral(f, x)
會計算不定積分 \(\int f\ dx\) -
integral(f, x, a, b)
則會計算定積分 \(\int _a^b f\ dx\)。注意參數缺失會導致錯誤
例如 integral(x^3,x)
\(= \frac {1}{4} x^4\)
Jacobian [#290]
- November 22, 2024
- Lîm Tsú-thuàn
Jacobian [#290]
- November 22, 2024
- Lîm Tsú-thuàn
多變數函數還可以求 Jacobian
f = (x*cos((1-z^2)*θ) - y*sin((1-z^2)*θ), x*sin((1-z^2)*θ) + y*cos((1-z^2)*θ), z) jacobian(f, (x,y,z))\[\begin {bmatrix} \cos ((1 - z^2)θ) & -\sin ((1 - z^2)θ) & 2yzθ \cdot \cos ((1 - z^2) θ) + 2xzθ \cdot \sin ((1 - z^2)θ) \\ \sin ((1 - z^2)θ) & \cos ((1 - z^2)θ) & -2xzθ \cdot \cos ((1 - z^2) θ) + 2yzθ \cdot \sin ((1 - z^2)θ) \\ 0 & 0 & 1 \end {bmatrix}\]
用 effect handler 實作 parser combinator [cs-001N]
- September 23, 2024
- Lîm Tsú-thuàn
用 effect handler 實作 parser combinator [cs-001N]
- September 23, 2024
- Lîm Tsú-thuàn
這些程式碼都是使用 OCaml 實現,並使用了 algeff 與 asai 程式庫
解析器需要完成的任務就是根據規則把一系列 tokens 變成文法樹,並且回報為何解析失敗,一般大學作業等級的編譯器都會讓學生直接使用解析器生成器,如 menhir 這種工具。然而實際上開發真實語言的解析器時,往往會遇到需要錯誤恢復並繼續解析,最後再回報多個錯誤的要求,這時候生成器往往給出很差的結果,甚至乾脆就是做不到的。
然而,手工編寫的解析器通常可維護性相當差劣。一種折衷的方案是所謂的解析器組合子,我過去也曾經介紹過如何利用組合子抽象掉重複的解析規則。但這種方案有個問題,就是回溯必須手動使用 try
組合子來在失敗時恢復狀態,但實務上這創造了相當難以理解的各種 try
安插,當我意識到這是因為 API 需要是兩階段的問題時,我就發現其實 effect handler 正是解決這個問題的好方法。
我本來是直接使用 Effect.Deep
的,但後來發現這種情境直接用 algeff 就足夠了,因此改採這個方案。實際程式碼如下
module Tokens = struct type t = Lexer.token Asai.Range.located list end module TokenState = Algaeff.State.Make (Tokens)
首先,我假設了 Lexer.token
這個型別存在,並且使用者會輸入一個標記過位置的 token list
。接著建立一個狀態模組,這個模組的只有三個用法:
let next_token () = match TokenState.get () with | [ eof ] -> eof | tok :: buf -> TokenState.set buf; tok | [] -> raise Impossible let shift pos = TokenState.set pos let current_position () = TokenState.get ()
這段程式巧妙的使用了 OCaml 的不可變 list 的特性,也就是持頭就可以保證資料不被回收
並且提供啟動函數
let run (init : Lexer.token Asai.Range.located list) (f : unit -> 'a) : 'a = TokenState.run ~init @@ fun () -> f ()
輔助函數. Asai 的例外捕捉 [#244]
- September 23, 2024
- Lîm Tsú-thuàn
輔助函數. Asai 的例外捕捉 [#244]
- September 23, 2024
- Lîm Tsú-thuàn
let catch_parse_error (p : unit -> 'a) : 'a option = let pos = current_position () in Reporter.try_with ~fatal:(fun d -> match d.message with | Parse_error -> shift pos; None | _ -> Reporter.fatal_diagnostic d) (fun () -> Some (p ()))
其中 Parse_error
跟 Reporter
都是使用者自訂的錯誤回報模組內容,如何定義可以參考 asai 的文件。這段輔助函數之所以出現只是為了讓讀者知道這個函數的存在,這個函數只捕捉解析失敗,讓其他錯誤繼續往上走。
常見的組合子 [cs-001O]
- September 23, 2024
- Lîm Tsú-thuàn
常見的組合子 [cs-001O]
- September 23, 2024
- Lîm Tsú-thuàn
直接消耗一個符合預測的 token consume
[#237]
- September 23, 2024
- Lîm Tsú-thuàn
直接消耗一個符合預測的 token consume
[#237]
- September 23, 2024
- Lîm Tsú-thuàn
let consume (predict : Lexer.token) : unit = let tok = next_token () in if tok.value == predict then () else # raise ...
重複解析到失敗為止 many
[#238]
- September 23, 2024
- Lîm Tsú-thuàn
重複解析到失敗為止 many
[#238]
- September 23, 2024
- Lîm Tsú-thuàn
let rec many (p : unit -> 'a) () : 'a list = let x = catch_parse_error p in match x with | None -> [] | Some x -> x :: many p ()
若失敗就解析第二個規則 [#239]
- September 23, 2024
- Lîm Tsú-thuàn
若失敗就解析第二個規則 [#239]
- September 23, 2024
- Lîm Tsú-thuàn
let ( <|> ) (p1 : unit -> 'a) (p2 : unit -> 'a) () : 'a = match catch_parse_error p1 with | None -> p2 () | Some x -> x
此外也有更複雜的錯誤恢復機制
如果最上層的定義解析失敗就紀錄失敗訊息並跳到下一個 start token 繼續解析 [#245]
- September 23, 2024
- Lîm Tsú-thuàn
如果最上層的定義解析失敗就紀錄失敗訊息並跳到下一個 start token 繼續解析 [#245]
- September 23, 2024
- Lîm Tsú-thuàn
let rec program () = let x = catch_parse_error top in match x with | Some x -> x :: program () | None -> let pos = next_start_token () in shift pos; program ()
Elaboration zoo 中的合一演算法與隱式參數 [cs-001K]
- September 22, 2024
- Lîm Tsú-thuàn
Elaboration zoo 中的合一演算法與隱式參數 [cs-001K]
- September 22, 2024
- Lîm Tsú-thuàn
程式語言為了讓使用者省略不必要的輸入,必須為使用者推導內容,這種需求催生了合一這種類型的演算法。比如很多程式語言允許泛型,比如下面的 OCaml 程式碼
let id (x : 'a) : 'a = x
Elaboration zoo 這個教學專案,它的程式碼要解決的,是一類更複雜的程式語言,叫做 dependent type 的系統中的合一問題,這類系統最重要的特性,就是類型也只是一種值,值也因此可以出現在類型中,但這就比較不是本篇的重點,有興趣的讀者可以閱讀 The Little Typer 來入門。在解釋完它的合一之後,我會介紹它隱式參數的解決方案
合一演算法的過程 [cs-001L]
- September 22, 2024
- Lîm Tsú-thuàn
合一演算法的過程 [cs-001L]
- September 22, 2024
- Lîm Tsú-thuàn
假設有程式碼
let id {A : U} (x : A) : A := x let id2 {B : U} (x : B) : B := id _ x
這裡 id _ x
中的底線就是表示「省略的引數」,被稱為 hole,我們並沒有明確的給它 B
。在展開這個 hole 時,我們用 meta variable ?0
替換它。但 meta variable 必須考慮 contextual variables 的 rigid form,因此進行套用得到 ?0 B x
這引發問題
什麼是 contextual variables?為什麼 contextual variables 是 B 與 x? [#635]
- September 22, 2024
- Lîm Tsú-thuàn
什麼是 contextual variables?為什麼 contextual variables 是 B 與 x? [#635]
- September 22, 2024
- Lîm Tsú-thuàn
答案是,這些是 ?0 能看到且實際內容未知的變數,只能用 rigid form 替代
什麼是 rigid form? [#636]
- September 22, 2024
- Lîm Tsú-thuàn
什麼是 rigid form? [#636]
- September 22, 2024
- Lîm Tsú-thuàn
rigid form 是 dependent type 中即使是 open term 也必須先進行計算而被迫在實作中出現的一種值;由於 meta variable 而被迫出現的值則叫做 flex form
現在我們手上有的 term 是 id (?0 B x) x
,現在執行 id (?0 B x)
,我們得到型別為
的 term
\[ \lambda x. x \]注意到 \((x\ :\ (?0\ B\ \textcolor {red}{x}))\) 中兩個 \(x\) 來源不同,不可混用,我用顏色表示它們的 scope 其實不同這件事
現在進入到把這個 term 套用到 x 上的環節了,因此觸發 \(x\ :\ B\) 是否是 \(?0\ B\ x\) 的 term 的合一計算,我們概念上紀錄成
\[ ?0\ B\ x \stackrel {?}{=} B \]現在合一演算法必須找出合適的 \(?0\) 來滿足等式。我們知道 \(?0\) 應該是某種 lambda
\[ \lambda 1. \lambda 2. \fbox {?} \],顯然 \(\fbox {?} = 1\) 就會給出我們想要的答案,但這部分要怎麼做到?elaboration zoo 的演算法分成三個階段
Invert [#637]
- September 22, 2024
- Lîm Tsú-thuàn
Invert [#637]
- September 22, 2024
- Lîm Tsú-thuàn
這裡的重點是,既然 \(?0\) 已經套用了 \(B\) 與 \(x\),因此就創立關聯它所創立的 lambda 變數到其 contextual variables 的 map
1 -> B 2 -> x
現在右手邊的 term 只需要看自己的每個 rigid form 有沒有被指向,只要這個 map 裡面查找到有變數是指向 rigid form 自己即反過來創立 rigid form 指向新名字的 map
Rename [#638]
- September 22, 2024
- Lîm Tsú-thuàn
Rename [#638]
- September 22, 2024
- Lîm Tsú-thuàn
因為我們右手邊的 term 是一個 rigid form \(B\),因此 map 是
B -> 1
用第二個 map 去改寫右手邊 term \(B\) 的內容,這樣我們就得到 \(\fbox {?} = 1\)
Lambda 化 [#639]
- September 22, 2024
- Lîm Tsú-thuàn
Lambda 化 [#639]
- September 22, 2024
- Lîm Tsú-thuàn
最後進行 abstraction,就得到了
\[ \lambda 1. \lambda 2. 1 \]
隱式參數的方法 [cs-001M]
- September 22, 2024
- Lîm Tsú-thuàn
隱式參數的方法 [cs-001M]
- September 22, 2024
- Lîm Tsú-thuàn
在最開始的程式碼
let id {A : U} (x : A) : A := x let id2 {B : U} (x : B) : B := id _ x
裡面,其實 {}
中的綁定叫做隱式參數,這表示我們其實也可以用 id x
來調用該函數。但這時候要怎麼知道需要補一個 hole 進去呢?elaboration zoo 作者提出的簡易方案就是區分 implicit \(\Pi \) type 與 implicit application,如此一來,當一個 implicit \(\Pi \) type 被 explicit apply 的時候,我們就知道要安插 hole 了
以 id x
而言,如果要明確的用 implicit 調用它,就必須寫成 id {B} x
,在語法就進行明確的區分。
這時候跳回去看「contextual variables 是 \(?0\) 能看到且實際內容未知的變數」就更能了解其理由了,因為已經能明確知道其內容的變數,如
let x = t
x
就是指向 t
的情況,若右手 term 是 x
,其實也會是 t
去進行 unify。若右手 term 已經是 rigid form 又可參照,就更不需要成為 contextual variables,因為其 solution 就是把右手 term 原封不動放入,在反轉 map 的時候,只要記得這個 rigid 是非 contextual,就可以為它寫一個 identity mapping。
Racket 中的有界續延如何實作 effect system 的功能? [cs-001I]
- August 27, 2024
- Lîm Tsú-thuàn
Racket 中的有界續延如何實作 effect system 的功能? [cs-001I]
- August 27, 2024
- Lîm Tsú-thuàn
討論如何用 racket 中的 continuation 實作 effect system 的概念
一個 effect system 大概做了什麼,我們從 effekt 語言的案例開始理解
- 一個簽名
effect yield(v : Int) : Bool
- 一個 handler
try { ... } with yield { n => ...; resume(n < 10) }
- 在
try
區塊中調用的函數f
可以用do yield(k)
來調用 handler - 當
f
執行到do yield(k)
,就會跳轉到with yield
中繼續進行,並且n = k
- 當程式執行到
resume
就會跳回去f
之後的do yield(k)
的續延繼續執行
事實上,exception 系統也可以實現成,沒有調用 resume 的 effect handler,讀者或許也已經想出數種使用方法了吧?這正是 effect system 的魅力。racket 擁有比 effect handler 更複雜的機制(continuation with marks),不過 effect handler 機制有保障使用者不容易出錯的好處,因此在 racket 中模擬一套 effect system 就有它的意義,並且是有趣的挑戰。
call/prompt
[racket-0005]
- August 27, 2024
call/prompt
[racket-0005]
- August 27, 2024
call/prompt
的主要功能,就如其名稱,是為被呼叫的函數提示一個標記,這個標記在 abort/cc
會被使用。完整的 call/prompt
調用是
(call/prompt f tag handler args ...)
f
是被調用的函數,中間的 tag
是標記,handler
是處理標記的函數,剩下的都是 f
的參數。讀者可以想像成
(with-handler [tag handler] (f args ...))
abort/cc
[racket-0006]
- August 27, 2024
abort/cc
[racket-0006]
- August 27, 2024
abort/cc
的調用是
(abort/cc tag vs ...)
tag
當然就是先前 prompt 寫進去的 tag
,而 vs ...
會用來呼叫 handler
(handler vs ...)
Continuation prompt tag 的產生方式 [racket-0008]
- August 27, 2024
Continuation prompt tag 的產生方式 [racket-0008]
- August 27, 2024
調用 (make-continuation-prompt-tag)
產出,這個函數還可以接受一個 symbol 產生可讀的識別碼,並且每次調用這個函數,產生的 tag 都算是不同的 tag,勿必要儲存好這個實體。
要想實現 exception 目前的程式已經完全充分了,只要寫下
(define (f params ...) (abort/cc tag "cannot read file ...")) (call/prompt f tag (λ (err) (printf "got err ~a~n" err)) args ...)
即可。事實上 racket 自身的的 exception 也是這樣實作的,要考慮的問題是,前面我們看過 resume
可以跳回去被呼叫的函數!這是如何做到的?
call/cc
[racket-0007]
- August 27, 2024
call/cc
[racket-0007]
- August 27, 2024
call/cc
這個函數是 call with current continuation 的意思,比如說在下面的程式碼中
(* 2 1)
1
的 continuation 就是把 1
挖掉留下的 (* 2 hole)
,故下列程式碼
(* 2 (call/cc (λ (k) (k 1))))
的結果是 2
。讀者可以想像 k = λ (hole) (* 2 hole)
,這在實作上不太正確,但對理解很有幫助。
一般來說,racket 的函數會簡單的寫成
(define (f params ...) stmt1 ... stmtn)
如果我在其中安放一個 call/cc
會發生什麼事呢?
(define (f params ...) ... (call/cc (λ (k) ...)) stmtk ...)
答案是 k = λ () (begin stmtk ... stmtn)
。由於 racket 自動把
stmt1 ... stmtn
包裝成 (begin stmt1 ... stmtn)
,而
(begin stmt1 stmt2 ...)
中 stmt1
的 continuation 是 (begin stmt2 ...)
,以此類推就很容易理解 k
等於什麼了。
我們正是需要使用 call/cc
來做出 resume 的效果。
實現 resume [#268]
- August 27, 2024
- Lîm Tsú-thuàn
實現 resume [#268]
- August 27, 2024
- Lîm Tsú-thuàn
在 f
中我們寫下
(define (f params ...) (call/cc (λ (k) (abort/cc tag k ...))))
在 call/prompt
的 handler 中新增一個 resume
參數,這樣就完成了。讀者可以填補下面的程式中的空白來檢驗結果,也充當練習
(define (f params ...) (call/cc (λ (k) (abort/cc tag k ...))) ...) (call/prompt f tag (λ (resume ...) ... ; 跳回 f 繼續 (resume)) args ...)
到這裡我們已經有了運行的基礎,要改善有幾個方向可以參考
- 用 macro 包裝語法
- 放到 typed/racket 中加上 effect 類型檢查確保使用者沒有漏掉 handler
- 支持 finally handler,保證任何退出行為都會被這個 handler 攔截(考慮 racket 的函數
dynamic-wind
)
我們下次見。
Interact with webmention.io [webmention-0003]
- August 10, 2024
- Lîm Tsú-thuàn
Interact with webmention.io [webmention-0003]
- August 10, 2024
- Lîm Tsú-thuàn
As I told in integrate forster site with existed webmentions tools, I will explain how to interact with API of webmention.io. Basically, you send a HTTP GET to the link below
https://webmention.io/api/mentions.jf2?domain=<your domain>&token=<your token>
You can get token at setting page, the result you will get will be like below
{ "type": "feed", "name": "Webmentions", "children": [ ... ] }
each children is
{ "type": "entry", "author": { "type": "card", "name": ..., "photo": ..., "url": ... }, "url": <source>, "published": null, "wm-received": ..., "wm-id": ..., "wm-source": ..., "wm-target": <target>, "wm-protocol": "webmention", "like-of": <target>, "wm-property": "like-of", "wm-private": false }
so you can parse this JSON and produce mention HTML for each target, and if you don't want to pull the whole feed, you can set since
as below
https://webmention.io/api/mentions.jf2?domain=<your domain>&token=<your token>&since=<time>
time format 2017-06-01T10:00:00-0700
. Of course, if you would not like to manage these mentions by hand, you can also consider my project webmention_db, which maintains mentions data for you at local.
Integrate forster site with existed webmentions tools [webmention-0002]
- July 31, 2024
- Lîm Tsú-thuàn
Integrate forster site with existed webmentions tools [webmention-0002]
- July 31, 2024
- Lîm Tsú-thuàn
Discuss how to make webmentions worked for forester.
This is a following post of the concept of webmention and forester, show how can you integrate a forester site with existed webmentions tools. To provide webmentions, the document must have a <link>
to provide webmention endopint, you don't have endpoint at this moment, that's why we need webmention.io
Get endopint via webmention.io (receiver service) [#269]
- July 31, 2024
- Lîm Tsú-thuàn
Get endopint via webmention.io (receiver service) [#269]
- July 31, 2024
- Lîm Tsú-thuàn
Go to webmention.io, there is a Web Sign-In form, put your <domain>
into it. Then it would load email via indie auth (you must provide the following content in index.html
for it)
<head> <link rel="me" href="mailto:your-mail">your-mail</a> <link rel="me" href="your-mastodon">Mastodon</a> <!-- you still haven't have endopint, just remind you once get one, back to here to insert it --> <link rel="webmention" href="<endpoint>" /> </head>
then send you a verify mail, after you login and click sites tab you will see a picture like
Click Get Setup Code, then you will see link like below
https://webmention.io/<domain>/webmention
that's the <endpoint>
for your site. We need to put it into tree.xsl
<head> …… <link rel="webmention" href="<endpoint>" /> …… </head>
If you want to send POST request to webmention.io manually, then here we already complete, but if you want to combine social media, we need to do more.
Bridgy [#270]
- July 31, 2024
- Lîm Tsú-thuàn
Bridgy [#270]
- July 31, 2024
- Lîm Tsú-thuàn
bridgy is a complex service, it plays several roles, but use it is relatively easy. At home page, you should see
I only use mastodon as example, you click the mastodon button, then get
click Cross-post to a Mastodon account..., unless your site is also a fediverse instance and know what to do. Then it would list your accounts (connected to bridgy) at Click to open an account you're currently logged into, go for one then you would see a form Enter post URL:, that's the place to give it your post link, but no rush, we need to prepare something.
- First, we cannot use
https://domain/xxx.xml
(I open an issue for this) - second, we haven't prepare proper document.
Microformat [#271]
- July 31, 2024
- Lîm Tsú-thuàn
Microformat [#271]
- July 31, 2024
- Lîm Tsú-thuàn
To make a https://domain/xxx.html
be a proper document, we must provide microformat, so you will need to macro
\def\hentry[descrption]{ \<html:div>[class]{h-entry}[hidden]{true}{ \<html:p>[class]{e-content}{ \descrption } } }
and invoke \hentry{describe the tree}
in every tree that you want to provide webmentions.
Now, your tree has proper content, the final step is using xsltproc
xsltproc default.xsl xxx.xml > xxx.html
to provide html version for post, then cross post html link on bridgy.
If all correct, you will be able to see the Dashboard of webmention.io has a list of reactions, which is made by people click like, repost, or reply your toot on mastodon. You might wondering do I missing something here? Yes, we want webmentions because we want to show reactions on our site, we will interact with webmention.io's APIs to collect mentions data, so that we can show them, that will be the next post.
The concept of webmention and forester [webmention-0001]
- July 30, 2024
- Lîm Tsú-thuàn
The concept of webmention and forester [webmention-0001]
- July 30, 2024
- Lîm Tsú-thuàn
Discuss how can we implement a webmention receiver for forester.
Each post in forester will be a xml (let's use my site as the example https://dannypsnl.me/xxx.xml
), post should provide the following content in <head></head>
<link href="https://dannypsnl.me/webmention-endpoint" rel="webmention" />
Sender view [#272]
- July 30, 2024
- Lîm Tsú-thuàn
Sender view [#272]
- July 30, 2024
- Lîm Tsú-thuàn
According to webmention spec, if someone tries to notify my site that there is a link mentions my post, then she has to do the following:
-
curl -I https://dannypsnl.me/xxx.xml
to get my webmention endpoint in thehead
- post the data, where
<link>
is the link refers to my postPOST /webmention-endpoint HTTP/1.1 Host: dannypsnl.me Content-Type: application/x-www-form-urlencoded source=<link> target=https://dannypsnl.me/xxx.xml
Receiver view [#273]
- July 30, 2024
- Lîm Tsú-thuàn
Receiver view [#273]
- July 30, 2024
- Lîm Tsú-thuàn
Therefore, a receiver is a POST
handler. According to spec, we can
- return http code
201
withLocation
in header pointing to the status URL - return http code
202
and asynchronously perform the verification - return http code
200
and synchronously perform the verification (not recommended), by section 3.2.2Webmention verification should be handled asynchronously to prevent DoS (Denial of Service) attacks.
Verification [#274]
- July 30, 2024
- Lîm Tsú-thuàn
Verification [#274]
- July 30, 2024
- Lîm Tsú-thuàn
- The receiver must check that
source
andtarget
are valid URLs [URL] and are of schemes that are supported by the receiver. (Most commonly this means checking that thesource
andtarget
schemes are http or https). - The receiver must reject the request if the
source
URL is the same as thetarget
URL. - The receiver should check that
target
is a valid resource for which it can accept Webmentions. This check should happen synchronously to reject invalid Webmentions before more in-depth verification begins. What a "valid resource" means is up to the receiver. For example, some receivers may accept Webmentions for multiple domains, others may accept Webmentions for only the same domain the endpoint is on.
If the receiver is going to use the Webmention in some way, (displaying it as a comment on a post, incrementing a like counter, notifying the author of a post), then it must perform an HTTP GET request on source
, following any HTTP redirects (and should limit the number of redirects it follows) to confirm that it actually mentions the target. The receiver should include an HTTP Accept header indicating its preference of content types that are acceptable.
Error response [#275]
- July 30, 2024
- Lîm Tsú-thuàn
Error response [#275]
- July 30, 2024
- Lîm Tsú-thuàn
If the Webmention was not successful because of something the sender did, it must return a 400 Bad Request status code and may include a description of the error in the response body.
However, hosting a receiver can be annoying, so the next post I will introduce how to build on the top of some existed tools.
用 docker compose 建立 hot reload 的 forest 筆記 [forester-000D]
- July 13, 2024
- Lîm Tsú-thuàn
用 docker compose 建立 hot reload 的 forest 筆記 [forester-000D]
- July 13, 2024
- Lîm Tsú-thuàn
建立 docker image [#248]
- July 13, 2024
- Lîm Tsú-thuàn
建立 docker image [#248]
- July 13, 2024
- Lîm Tsú-thuàn
Dockerfile 的內容
FROM ubuntu:oracular RUN apt-get update RUN apt install -y opam RUN apt install -y build-essential RUN opam init -y RUN git clone https://git.sr.ht/~jonsterling/ocaml-forester RUN cd ocaml-forester; opam pin -y . RUN apt install -y curl RUN curl https://sh.rustup.rs -sSf | \ sh -s -- --default-toolchain stable -y ENV PATH=/root/.cargo/bin:$PATH ENV PATH=/root/.opam/default/bin:$PATH RUN cargo install forest-server CMD [ "forest", "watch", "1313", "--", "build --dev dev.toml" ]
大致上就是下載 opam
、forest-server
等必要工具,然後指定指令監看檔案變化進行 reload。用 docker build . -t forest:latest
產出 image。
Configure docker compose [#249]
- July 13, 2024
- Lîm Tsú-thuàn
Configure docker compose [#249]
- July 13, 2024
- Lîm Tsú-thuàn
services: forest: image: "forest:latest" working_dir: "<hostpath/to/your-forest>" ports: - "1313:1313" labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`forest.localhost`)" - "traefik.http.routers.whoami.entrypoints=web" volumes: - "./:<hostpath/to/your-forest>" traefik: image: "traefik:v2.10" container_name: "traefik" command: - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" ports: - "80:80" # Web UI - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro"
<hostpath/to/your-forest>
這部分不能省略,因為這樣每篇 tree 中的 edit 按鈕才會是正確的 host 路徑。執行 docker compose up -d
啟動 containers。
最後你可以在 forest.localhost:1313
存取到 forest,之後就只需要修改跟新增 tree 即可。
避免寫死 host 路徑 [#250]
- July 13, 2024
- Lîm Tsú-thuàn
避免寫死 host 路徑 [#250]
- July 13, 2024
- Lîm Tsú-thuàn
如果真的不想寫死的話可以像我一樣用 YAML.jl 這一類的工具直接寫個小腳本搞定
using YAML forest_dir = pwd() data = YAML.load_file("blog.yml") data["services"]["blog"]["working_dir"] = forest_dir data["services"]["blog"]["volumes"] = ["./:$(forest_dir)"] YAML.write_file("docker-compose.yml", data)
無外部空間下如何考慮幾何空間的測量? [math-00C4]
- July 1, 2024
- Lîm Tsú-thuàn
無外部空間下如何考慮幾何空間的測量? [math-00C4]
- July 1, 2024
- Lîm Tsú-thuàn
自 g0v 貼文 改寫
metric 就是在測量長度。不過在歐式空間裡面討論嵌入其中的曲面時,曲面有外部空間切向量,也就是歐式空間的向量可以使用。如果曲面沒有外空間,就需要自己做一個出來,這就引出了 Riemann metric 的想法:對可微分流形 \(M\) 的每一點 \(p\) 考慮抽象的切空間 \(T_pM\)(不考慮 \(T_pM\) 到底是什麼),重點是隨點附上內積函數 \(g : T_pM \times T_pM \to R\),因為是模仿內積所以有 bilinearity, positive-definiteness, symmetry 等性質
現在考慮曲線 \(y : [0, 1] \to M\),在每一點度量 \(T_pM\) 向量並積分(加起來)即是曲線長度。又隨著區間 \(t : [0, 1]\) 改變,會有對應變化的 \(p\) 點,因此模仿並定義
\[ \text {length}(y) = \int _0^1 \sqrt {g( \frac {d y}{d t} , \frac {d y}{d t} )} dt \]\(\sqrt {g( \frac {d y}{d t} , \frac {d y}{d t} )}\) 是 norm 的定義,積分因為是跟著 \(t\) 變化,因此依賴 \(y\) 的參數 \(t\) 來定義。如此一來就可以問下一個問題:根據 g 是從 a 到 b 的最短曲線是誰,這就是曲面上的直線的概念(然而,全域與局部最短線,是不一樣的問題,考慮整體將會複雜許多)。
一個失敗的類型論 inductive types 定義方案 [tt-001O]
- April 28, 2024
- Lîm Tsú-thuàn
一個失敗的類型論 inductive types 定義方案 [tt-001O]
- April 28, 2024
- Lîm Tsú-thuàn
從上次提到之後,我到現在都會斷斷續續的思考這個問題。現在我認為 type pattern matching 在 dependent type 中是一個失敗的想法。或許這個方案只是太過複雜而非不能達成,但我認為目前缺點已經超過這套系統能帶來的好處。下面我會討論一些精簡的推導與相應的結果
- 在最早想到這個方案時,由於發現要避免多態性被打破,所以在一般 universe
U
之外要有一個特殊的 universe,之後會稱其為U-
。 - 因為每個
A : U-
身為型別與身為值不一樣,這需要一個區分用法的方式,可以考慮極化計算性作為解法,所以到這裡我還沒有停步。
然而,有一個特殊的規則是變數不能是 U-
,免得出現 stuck value 出現在 U-
的計算之中,但這在 type pattern match 的變數 case 中會出現,這裡是我開始認為這套系統沒機會的地方。關於這種情況,我有兩個想法
- 第一種是規定一種特殊的
U- or U
的選擇,讓型別定義可以用U
表示變數的情況,但這又讓型別 universe 更複雜了,我認為這個方向沒什麼機會。 - 第二種是放鬆只能在 inductive types 定義中使用
U-
的限制,因為這類 inductive types 必然不能被多態函數使用,因此放鬆使用位置之後就能寫出定義時是多態,而使用時必然是單態的新型態函數。這個方向還需要再限制不讓x : U-
是隱式參數,這樣就不可能有 stuck value 出現。
此外我沒有想到有什麼錯誤,但這複雜化了實際使用,所以到這裡我就暫時告一段落。
用 agda 玩翻杯子遊戲 [agda-0003]
- March 31, 2024
- Lîm Tsú-thuàn
- agda-0003.html
用 agda 玩翻杯子遊戲 [agda-0003]
- March 31, 2024
- Lîm Tsú-thuàn
- agda-0003.html
翻杯子遊戲是一個很有名的派對遊戲與典型的奇偶問題。遊戲從 3 個向下的杯子與 2 個向上的杯子開始,每次可以選兩個不同的杯子,被選中的杯子方向會翻轉,問是否有辦法反覆這個動作,得到五個向上的杯子。
Exercise. [#644]
- March 31, 2024
- Lîm Tsú-thuàn
Exercise. [#644]
- March 31, 2024
- Lîm Tsú-thuàn
在開始閱讀之前,你可以自己先想想看問題的方案。若有辦法達成,提出需要執行什麼步驟;若不可能達成,提出為何無法達成。
正如標題說的,我們想用 agda 來玩這個遊戲,所以需要知道怎麼用這個程式語言。
Tool. Agda 的開發工具 [agda-0005]
- April 1, 2024
- Lîm Tsú-thuàn
Tool. Agda 的開發工具 [agda-0005]
- April 1, 2024
- Lîm Tsú-thuàn
我使用的編輯器工具是 agda mode on VS Code,也可以用 emacs 之類的。常用操作有
-
ctrl+c
,ctrl+l
會編譯檢查檔案,假設程式中有?
,會被替換成所謂的 hole{! !}
,其實就是待寫的程式 -
ctrl+c
,ctrl+,
可以窺看 hole 的目標類型,與當前 context 有哪些 term 可用 -
ctrl+c
,ctrl+r
會把 hole 中你打的程式碼往前提取,當然前提是類型是正確的 -
ctrl+c
,ctrl+m
會把 hole 中你打的程式碼直接當成結果,一樣類型要是正確的 - 一般來說一個 agda 定義如下
hello : A → B hello a = {! !}
ctrl+c, ctrl+c 會問你要把哪個變數用構造子分開,回答a
,假設有a1
與a2
兩個構造子,程式就會變成hello : A → B hello a1 = {! !} hello a2 = {! !}
Collary. 本篇出現的符號輸入 [#645]
- March 31, 2024
- Lîm Tsú-thuàn
Collary. 本篇出現的符號輸入 [#645]
- March 31, 2024
- Lîm Tsú-thuàn
\bN |
ℕ |
---|---|
\bP |
ℙ |
\:: Vector 類型的串接符號 |
∷ |
\_1 表示下標 1 |
₁ |
\^1 表示上標 1 |
¹ |
\^- 表示上標負號 |
⁻ |
\equiv |
≡ |
\nequiv |
≢ |
\< |
≡⟨⟩ 中的 ⟨ |
\> |
≡⟨⟩ 中的 ⟩ |
\r 函數類型的分隔符 |
→ |
\Gl 匿名函數的開頭 |
λ |
建立模型 [#646]
- March 31, 2024
- Lîm Tsú-thuàn
建立模型 [#646]
- March 31, 2024
- Lîm Tsú-thuàn
由於每次要找兩個杯子做翻轉,而且杯子只有上跟下的分別,因此我們可以考慮用 Data.Parity
來表示杯子的狀態,其中 _⁻¹
表示可以翻轉杯子,所以引用
open import Data.Parity.Base open import Data.Parity.Properties
接著,五個杯子可以用 vector 表示,所以引入模組並定義
open import Data.Nat open import Data.Vec open import Data.Vec.Properties _Cups : ℕ → Set n Cups = Vec Parity n
現在,我們可以寫下初始狀態與目標狀態
open Parity initS : 5 Cups initS = 0ℙ ∷ 0ℙ ∷ 1ℙ ∷ 1ℙ ∷ 0ℙ ∷ [] target : 5 Cups target = 1ℙ ∷ 1ℙ ∷ 1ℙ ∷ 1ℙ ∷ 1ℙ ∷ []
猜想與結論 [#647]
- March 31, 2024
- Lîm Tsú-thuàn
猜想與結論 [#647]
- March 31, 2024
- Lîm Tsú-thuàn
為了證明從 initS
到 target
是不可能的
- 需要考慮根據「找兩個杯子翻轉實際上有可能達成的所有結果」。
- 此外,如
0ℙ ∷ 0ℙ ∷ 1ℙ ∷ 1ℙ ∷ 0ℙ
與0ℙ ∷ 0ℙ ∷ 1ℙ ∷ 0ℙ ∷ 1ℙ
之間的差異於我們無關緊要。
由於可能的杯子狀態只有 0ℙ
跟 1ℙ
,所以可能的選擇有
-
(0ℙ, 0ℙ)
到(1ℙ, 1ℙ)
-
(0ℙ, 1ℙ)
到(1ℙ, 0ℙ)
-
(1ℙ, 0ℙ)
到(0ℙ, 1ℙ)
-
(1ℙ, 1ℙ)
到(0ℙ, 0ℙ)
中間兩個是 identical 的轉換,由於我們上面討論的第二點,他們不會對狀態造成改變;第一個會把原封不動變成翻轉兩次,最後一個把翻轉兩次變成不動。所以綜合而論就是,若把 n Cups
中的 Parity
全部直接加起來,就能夠分辨狀態是否有可能互換,據此定義 χ
函數。
χ : ∀ {n} → n Cups → Parity χ [] = 0ℙ χ (x ∷ cups) = χ cups + x
因此只論遊戲目的,下面的兩個事實就已經證明答案是不可能達成,因為兩者的奇偶性不同,然而我們唯一能做的動作不會改變奇偶性。
lemma₁ : χ initS ≡ 0ℙ lemma₁ = refl lemma₂ : χ target ≡ 1ℙ lemma₂ = refl
推廣結果 [#648]
- March 31, 2024
- Lîm Tsú-thuàn
推廣結果 [#648]
- March 31, 2024
- Lîm Tsú-thuàn
但我們還想要知道廣泛的來說,如何將事實表現成定理,並且應用到任意 n Cups
上,因此有
theorem : ∀ {n} → (i j : Fin n) → (a : n Cups) ------------------------------------------------ → χ ((a [ i ]%= _⁻¹) [ j ]%= _⁻¹) ≡ χ a theorem i j a = begin χ (updateAt (updateAt a i _⁻¹) j _⁻¹) ≡⟨ lemma j (a [ i ]%= _⁻¹) ⟩ χ (updateAt a i _⁻¹)⁻¹ ≡⟨ ⁻¹-selfInverse (sym (lemma i a)) ⟩ χ a ∎ where open ≡-Reasoning open Lemma
其意義是,對任意有限多個杯子進行兩次翻轉,奇偶性不變。這個定理比實際遊戲進行的行為更廣泛一些,i ≢ j
才是對應現實中的翻杯子行為,因為選擇是先進行的,而翻轉是同時做。但因為對同一杯子翻轉兩次也不會改變奇偶狀態,所以 i ≡ j
也行。其中
-
a [ i ]%= _⁻¹
表示對a
的位置i
套用翻轉函數。 -
x ≡ y
表示要證明x
等於y
。 -
begin
到∎
用來寫出等式替換的過程,程式a ≡⟨ lemma ⟩ b
的意義是,根據lemma
可知a ≡ b
。這些程式要通過引用open import Relation.Binary.PropositionalEquality
並使用open ≡-Reasoning
來存取。 - 這裡出現的
Fin n
需要引用open import Data.Fin
由於跟Data.Nat
有名稱衝突,需要用using
跟renaming
控制引用的符號。
Exercise. [#649]
- March 31, 2024
- Lîm Tsú-thuàn
Exercise. [#649]
- March 31, 2024
- Lîm Tsú-thuàn
上面的 open Lemma
是一個內部模組,下面留空讓你自行證明
module Lemma where lemma : ∀ {n} → (i : Fin n) → (a : n Cups) ---------------------------------------------------------- → χ (a [ i ]%= _⁻¹) ≡ χ a ⁻¹ lemma i a = {! !}
Conclusion. [#650]
- March 31, 2024
- Lîm Tsú-thuàn
Conclusion. [#650]
- March 31, 2024
- Lîm Tsú-thuàn
結論當然還可以再推廣,例如不再是翻兩個而是三個杯子呢?假使奇偶相同,只做某動作就一定能得到某狀態嗎?或是假使動作能改變奇偶性,是否就一定能達成某狀態呢?把玩想像構物的有趣之處,歡迎自行體驗。
使用 TLA+ 的第一步 [tlaplus-0002]
- March 27, 2024
- Lîm Tsú-thuàn
使用 TLA+ 的第一步 [tlaplus-0002]
- March 27, 2024
- Lîm Tsú-thuàn
由於很多 TLA+ 入門教學似乎都沒有談到實務上要從哪裡開始使用 TLA+,所以這裡我想介紹實際上要怎麼做。一個 TLA+ 的檔案以 .tla
為副檔名,其中由 --- MODULE name ---
開頭,由 ===
結尾,例如
---- MODULE plustwo ---- =====
在其中可以引用模組,寫成 EXTENDS xxx, yyy, ...
---- MODULE plustwo ---- EXTENDS Integers =====
使用 PlusCal 語言 [#265]
- March 27, 2024
- Lîm Tsú-thuàn
使用 PlusCal 語言 [#265]
- March 27, 2024
- Lîm Tsú-thuàn
比起直接寫出 Spec
等不變式,先寫 PlusCal language 的程式再使用用它生成的 Spec
不變量會更簡單也更實用。因為 TLA+ 會嘗試生成所有可能的狀態,有可能出現所謂的 unbound model,就結果而言對它進行檢查永遠不會完成。用 PlusCal 語言寫的程式相對容易發現這種錯誤。
---- MODULE plustwo ---- EXTENDS Integers CONSTANT Limit (* --algorithm plustwo variables x = 0; begin while x < Limit do x := x + 2; end while; end algorithm; *) \* BEGIN TRANSLATION (chksum(pcal) = "3f62e9ff" /\ chksum(tla) = "239a9ecd") \* END TRANSLATION =====
由 PlusCal 產出的不變量會被包在 BEGIN TRANSLATION
到 END TRANSLATION
裡面,可以發現它還會檢查 checksum。由於這個區塊內的程式會被機器生成的內容覆蓋,要記得千萬不要把自己寫的不變量放在這裡面。
上面的 CONSTANT Limit
可以在 model 的設定檔 .cfg
中指定,這是為了避免把常數寫死在 TLA+ 主程式中,好在檢查前可以進行修改。
增加自己的不變量 [#266]
- March 27, 2024
- Lîm Tsú-thuàn
增加自己的不變量 [#266]
- March 27, 2024
- Lîm Tsú-thuàn
在有了這些程式之後,可以開始增加自己的不變量
Even(x) == x % 2 = 0 IsInc == x >= 0 Inv == IsInc /\ Even(x) THEOREM Terminated == Spec => Termination
-
IsInc
要求x
總是大於初始值0
-
Even(x)
要求我們寫的程式只會產生偶數 -
Inv
把所有我們想證明的不變量組合在一起,/\
表示邏輯的「a 且 b」語句。我想很容易猜到\/
表示邏輯的「a 或 b」語句
THEOREM
部分宣告 Spec
蘊含 Termination
不變量,這兩者都是 PlusCal 產生的,所以不用太在意細節,這裡的意義是證明程式確實會終止。
Conclusion. [#267]
- March 27, 2024
- Lîm Tsú-thuàn
Conclusion. [#267]
- March 27, 2024
- Lîm Tsú-thuàn
這裡介紹了 TLA+ 如何運作,TLA+ 對現實程式的幫助會體現在編寫非同步的程式時,TLA+ 擅長對只有有限狀態、可以使用經典邏輯推導的程式進行檢查,主要可以發現死鎖與違反不變式等錯誤。對 TLA+ 所使用的數學方面的學習可以參考 Lamport 本人寫的 A Science of Concurrent Programs。
滿足 \(\text {null }T = \text {range }T\) 的矩陣 \(T : \R ^4 \to \R ^4\) [linear-000C]
- March 24, 2024
- Lîm Tsú-thuàn
滿足 \(\text {null }T = \text {range }T\) 的矩陣 \(T : \R ^4 \to \R ^4\) [linear-000C]
- March 24, 2024
- Lîm Tsú-thuàn
在我最早的想法中,根據 \(\text {range }T = \text {null }T\),可以看出 \(T(Tv) = 0\) 對所有 \(v \in \R ^4\) 成立。因此,可以假設
\[ T = \begin {bmatrix} a_{11} & a_{12} & a_{13} & a_{14} \\ a_{21} & a_{22} & a_{23} & a_{24} \\ a_{31} & a_{32} & a_{33} & a_{34} \\ a_{41} & a_{42} & a_{43} & a_{44} \end {bmatrix} \]計算 \(TT\) 可以得
\[ T^2 = \begin {bmatrix} {a_{11}}^2 + a_{12}a_{21} + a_{13}a_{31} + a_{14}a_{41} & a_{11}a_{12} + a_{12}a_{22} + a_{13}a_{32} + a_{14}a_{42} & a_{11}a_{13} + a_{12}a_{23} + a_{13}a_{33} + a_{14}a_{43} & a_{11}a_{14} + a_{12}a_{24} + a_{13}a_{34} + a_{14}a_{44} \\ a_{11}a_{21} + a_{21}a_{22} + a_{23}a_{31} + a_{24}a_{41} & a_{12}a_{21} + {a_{22}}^2 + a_{23}a_{32} + a_{24}a_{42} & a_{13}a_{21} + a_{22}a_{23} + a_{23}a_{33} + a_{24}a_{43} & a14a_{21} + a_{22}a_{24} + a_{23}a_{34} + a_{24}a_{44} \\ a_{11}a_{31} + a_{21}a_{32} + a_{31}a_{33} + a_{34}a_{41} & a_{12}a_{31} + a_{22}a_{32} + a_{32}a_{33} + a_{34}a_{42} & a_{13}a_{31} + a_{23}a_{32} + {a_{33}}^2 + a_{34}a_{43} & a14a_{31} + a_{24}a_{32} + a_{33}a_{34} + a_{34}a_{44} \\ a_{11}a_{41} + a_{21}a_{42} + a_{31}a_{43} + a_{41}a_{44} & a_{12}a_{41} + a_{22}a_{42} + a_{32}a_{43} + a_{42}a_{44} & a_{13}a_{41} + a_{23}a_{42} + a_{33}a_{43} + a_{43}a_{44} & a14a_{41} + a_{24}a_{42} + a_{34}a_{43} + {a_{44}}^2 \\ \end {bmatrix} \]因此這裡就有了 16 個方程式。可以知道
\[ a_{i1} = \frac {-(a_{i2}a_{2j} + a_{i3}a_{3j} + a_{i4}a_{4j})} {a_{1j}} \]令 \(a_{1j} = 1\),得
\[ 1 = a_{11} = \frac {-(a_{i2}a_{2j} + a_{i3}a_{3j} + a_{i4}a_{4j})} {a_{11}} = -(a_{i2}a_{2j} + a_{i3}a_{3j} + a_{i4}a_{4j}) \]接著指定 \(a_{21} = 1, a_{31} = -1, a_{41} = -1\),得
\[ T = \begin {bmatrix} 1 & 1 & 1 & 1 \\ 1 & a_{22} & a_{23} & a_{24} \\ -1 & a_{32} & a_{33} & a_{34} \\ -1 & a_{42} & a_{43} & a_{44} \end {bmatrix} \]接著依次指定值滿足方程式,如
- \(1+a_{22}-a_{23}-a_{24} = 0\)
- \(-1+a_{32}-a_{33}-a_{34} = 0\)
- \(-1+a_{42}-a_{43}-a_{44} = 0\)
就可以湊出
\[ T = \begin {bmatrix} 1 & 1 & 1 & 1 \\ 1 & -1 & 1 & -1 \\ -1 & -1 & -1 & -1 \\ -1 & 1 & -1 & 1 \end {bmatrix} \]不過這個辦法適合求出具體的矩陣,卻很難用來證明任意次數的空間有或無這種線性變換的存在。有效率的方法是使用 rank-nullity,在限制下可以知道 \(\text {rank}\;T = 2 = \text {nullity}\;T\) 因此只對 \(2\) 個維度造成影響的矩陣都可以。同理可以推論奇數有限維度皆不滿足,故 \(\R ^5 \to \R ^5\) 滿足這個性質的矩陣不存在。
Component model 的基本案例 [software-0012]
- March 7, 2024
- Lîm Tsú-thuàn
Component model 的基本案例 [software-0012]
- March 7, 2024
- Lîm Tsú-thuàn
最基本的範例如下
(component (core module $M (func (export "dup") (param i64) (result i64) local.get 0 local.get 0 i64.add) ) (core instance $m (instantiate $M)) (func $run (param "a" s64) (result s64) (canon lift (core func $m "dup")) ) (export "mdup" (func $run)) )
這段程式碼以 .wat 的 component 擴展格式寫成,其意義是
- 宣告一個 core module,也就是原始的 wasm 格式,其中導出一個函數
dup
- 接著實例化 (instantiate) 這個 module,這裡可以發現 component model 的主要用途正是讓實例化可以被編程,成為其他高階工具的輸出內容,這裡的地位類似 linker script
- 接著,一個 instance 的函數就可以被 component 的函數包裝,只要用
canon lift
提升即可。不過要注意的是,如果函數帶有需要記憶體操作的簽名,例如有字串參數,就需要提供 memory 與 realloc 等參數,好讓 runtime 知道如何進行資料在不同 component 之間編碼傳遞 - 最後導出包裝函數,命名為
mdup
,外部的使用者就可以調用了
Example. Functor category 中的 monomorphism 不一定由 monomorphism 組成 [math-007Z]
- February 1, 2024
- Lîm Tsú-thuàn
Example. Functor category 中的 monomorphism 不一定由 monomorphism 組成 [math-007Z]
- February 1, 2024
- Lîm Tsú-thuàn
考慮 \(A\) 範疇是 \(0 \to 1\) 與 \(B\) 範疇,其中 \(fg=fh=k\) 但注意 \(f\) 不是 mono,因為這沒有蘊含 \(g=h\)
因此 functor category \([A,B]\) 是 \(B\) 的 arrow category。現在我們可以指出 natural transformation \((1_B, f) : (B,B)\to (B,C)\) 是 \([A,B]\) 中的 monomorphism,但其 component \(f\) 並不是 mono。要檢查 \((1_B,f)\) 是 mono 可以列出所有可以串在前面的 arrows,在這裡有四個。
對應的結果是 (左到右,上到下)
- \((fg,g) = (k,g)\)
- \((fh,h) = (k,h)\)
- \((f,g)\)
- \((f,h)\)
確實滿足 mono 的特性,\((1_B,f) \circ a = (1_B,f) \circ b\) 蘊含 \(a = b\)。
用 Catlab.jl 製作 wiring 圖 [software-000X]
- January 27, 2024
- Lîm Tsú-thuàn
用 Catlab.jl 製作 wiring 圖 [software-000X]
- January 27, 2024
- Lîm Tsú-thuàn
引用的程式庫
using Catlab.WiringDiagrams, Catlab.Graphics import Convex, SCS using Catlab.Theories
產生 wiring 圖的程式
A = Ob(FreeBiproductCategory, :A) g = (mcopy(A) ⊗ id(A)) ⋅ (id(A) ⊗ mmerge(A)) to_composejl(g)
g
是 monoidal category 的 morphism,to_composejl
會把它畫成 wiring diagram;也可以用 to_tikz
或是 to_graphviz
來畫。
要是想匯出到 latex 檔案中使用,可以參考下面的程式產生 tikz 程式。
import Catlab.Graphics: TikZ to_tikz(g) |> TikZ.pprint
什麼是編譯器? [cs-000Z]
- January 2, 2024
- Lîm Tsú-thuàn
什麼是編譯器? [cs-000Z]
- January 2, 2024
- Lîm Tsú-thuàn
要回答這個問題,就要先知道什麼是程式語言,然後我們才能在這個基礎上解釋編譯器的目的與定義。
程式語言是什麼? [cs-0010]
- January 2, 2024
- Lîm Tsú-thuàn
程式語言是什麼? [cs-0010]
- January 2, 2024
- Lîm Tsú-thuàn
一個程式語言必然是有語法,是有限語法規則構成的一種形式系統,與用作推理基礎的邏輯系統不同的是
- 一般不介意規則上的重複,同一個計算與多個規則對應非常的常見。例如迴圈與遞迴具有完全一樣的能力 (對應 PCF 的 \(\mu \)),但 racket 語言兩者皆有提供。
- 通常刻意追求可計算性 (也就是不一致),不過程式語言也可以不具備可計算性。
不具備計算規則的程式語言 [cs-0016]
- January 2, 2024
- Lîm Tsú-thuàn
不具備計算規則的程式語言 [cs-0016]
- January 2, 2024
- Lîm Tsú-thuàn
例如 XML 或是 JSON 等純標記語言就是刻意不設計對應的計算系統的。
有計算規則的程式語言 [cs-001A]
- January 2, 2024
- Lîm Tsú-thuàn
有計算規則的程式語言 [cs-001A]
- January 2, 2024
- Lîm Tsú-thuàn
以有計算規則為前提,則一個程式語言一般會有操作語意與指稱語意兩種描述方式。定位上,操作語意通常是實作程式語言時會參考的一組演繹規則,寫成相繼式,如
\[ \frac { \Gamma \vdash A \Downarrow u, B \Downarrow v }{ \Gamma \vdash A + B \Downarrow u + v } \]指稱語意是找出一組數學物件,並證明自己完全抽象了操作語意 (也就是滿足充分性定理),用來推理程式語言的行為的一個模型。細節在遞迴的表示一文中有描述,數學記號 \(\mathcal {C}\llbracket e \rrbracket \) 就是在描述一個接受語法,回傳相應的數學物件的指稱語意函數。另外可以進一步參考 Gunter 的書。
此外,有一些具有計算規則,但不要求要有通用計算性的語言,這一類語言通常被稱為宣告式。
宣告式的程式語言 [cs-0017]
- January 2, 2024
- Lîm Tsú-thuàn
宣告式的程式語言 [cs-0017]
- January 2, 2024
- Lîm Tsú-thuàn
HTML、css 在瀏覽器底下具有計算意義,用來產生對應的畫面。還有 Prolog 與 SQL 等語言,一般都只是宣告所謂的 query,並讓一些特定的求解系統自己計算答案。這層意義下 computer algebra system 或是 z3 這種 logic solver 都算是程式語言。
所以語法規則這部分的形式系統對程式語言來說必須存在,但描述計算的形式系統對則不是必要的,研究具有計算規則的程式語言對應的。
編譯器的角色 [cs-0011]
- January 2, 2024
- Lîm Tsú-thuàn
編譯器的角色 [cs-0011]
- January 2, 2024
- Lîm Tsú-thuàn
所以,編譯器其實只在語法規則與計算規則都有規範的程式語言上有意義,編譯器的意義是把目前程式語言的語法重新寫成目標語言的語法,所以讀者很可能聽過重寫系統這個說法。
硬體實現的計算系統 [cs-0012]
- January 2, 2024
- Lîm Tsú-thuàn
硬體實現的計算系統 [cs-0012]
- January 2, 2024
- Lîm Tsú-thuàn
電腦事實上是一種計算系統的物理案例,我們用電路把某種通用計算系統實現出來,用電訊號表示計算系統的計算結果。CPU 讀取指令進行相應電訊號發射,並將結果儲存在特定位置,這基本上就是現代電腦的運作機制。
組合語言與組譯器 assembly [cs-0013]
- January 2, 2024
- Lîm Tsú-thuàn
組合語言與組譯器 assembly [cs-0013]
- January 2, 2024
- Lîm Tsú-thuàn
但指令需要編碼才能被 CPU 讀取,因此會有一系列的數字與對應的指令,組合語言則是為了讓人類可以閱讀這些指令而設計的編碼,組譯器因此基本上只要直接把指令文字變成一連串數字即可!因此,可以看出組合語言確實是一種程式語言,而組譯器是最簡單的把語法變成數字語法的重寫系統,對應的計算系統則是電腦硬體執行的那個計算系統。
當然這省略了組譯器的模組化功能部分,不過這部分對理解組譯器的定位沒有什麼幫助。這部分是由被稱為 linker 的程式進行,把不同的物件檔連結起來,比較好的參考書籍有《Linker and Loader》
當然這時候有人會質疑,為什麼不要直接用數字指令,或是任意一種底層的可計算結構編寫計算就好呢?事實上,這種觀點等於在說他認為不需要有任何新的程式語言的發明,因為程式語言存在最主要的理由之一就是要賦予計算規則「好用的」語法規則,讓不同的開發者可以有效的用來溝通。現在,可以總結編譯器為,把程式語言重寫成另一種程式語言的系統!所以下面我們就有計算規則的這類程式語言,討論編譯器必須滿足哪些要求,與實現上的概覽。
Requirement. 不能改變計算語意 [cs-0014]
- January 2, 2024
- Lîm Tsú-thuàn
Requirement. 不能改變計算語意 [cs-0014]
- January 2, 2024
- Lîm Tsú-thuàn
也就是說如果一個語法 \(M\) 在當前的計算規則下應該得出 \(v\),那麼編譯之後得到的目標語法 \(M'\) 在目標計算系統裡面也應該算出 \(v\)。很不幸的是這件事通常沒這麼簡單,因為程式語言擁有的一些高級抽象很可能在組合語言這類語言裡面不存在,像 Bool
這種值在組合語言裡面常常就只是 \(0\) 與非 \(0\)。這導致我們本來就需要對這類抽象進行編碼,當涉及到連續記憶體配置時 (像是字串與陣列等),這件事就更難做對了。不過總之語意被改變一般被認為是一種編譯器的錯誤。
除了不改變語意,編譯器還需要達成一些額外的目標,其中一項就是根據資料盡可能的最佳化在目標計算系統上的執行速度、或是減少空間消耗等,不過第二項就我所知幾乎都是開發者的工作。
常見的最佳化策略 [cs-0015]
- January 2, 2024
- Lîm Tsú-thuàn
常見的最佳化策略 [cs-0015]
- January 2, 2024
- Lîm Tsú-thuàn
- 常數傳播與共通子運算式:這是一種簡單的靜態分析,主要想法就是通過代數約束找出已經計算過的資料,並盡量減少重複利用已經有的運算結果。
- 指令選擇:有些計算可以用不同指令組合達成,但某些計算組合比其他更快。
- 暫存器 (register) 分配:由於 CPU 操作 register 比讀取記憶體更快速,所以盡量把變數放在 register 可以減少執行時間。
- 表達式樹平衡:如果一個表達式的樹主要構成是二元計算指令,這時把樹調整成更平衡的形式再配置指令會加速,因為可以減少資料依賴、使用更多的 register。
- 迴圈常數倍展開:由於快取的關係,一次進行 4 或是 8 個計算會比再次載入執行更快。
- 多面體編譯:把資料相依性記錄成 lattice,幫沒有資料衝突的計算安排用不同的 CPU core 執行,跟迴圈與共通運算式的想法其實是類似的。
找出程式的錯誤 [cs-0018]
- January 2, 2024
- Lîm Tsú-thuàn
找出程式的錯誤 [cs-0018]
- January 2, 2024
- Lîm Tsú-thuàn
讀者現在應該了解編譯器的存在目的與一點點形式化的背景,可以進一步學習指稱語意或是最佳化策略來了解程式語言的各種面向,此外,可計算程式語言一般還需要能與環境互動,這部分本身就有相當的複雜性,或許未來能夠再寫一篇文章介紹。
方便的 CLI 軟體 [software-000R]
- December 28, 2023
- Lîm Tsú-thuàn
方便的 CLI 軟體 [software-000R]
- December 28, 2023
- Lîm Tsú-thuàn
Zoxide [software-000N]
- December 15, 2023
- Lîm Tsú-thuàn
- https://github.com/ajeetdsouza/zoxide
Zoxide [software-000N]
- December 15, 2023
- Lîm Tsú-thuàn
- https://github.com/ajeetdsouza/zoxide
Remark. [#286]
- December 15, 2023
- Lîm Tsú-thuàn
Remark. [#286]
- December 15, 2023
- Lîm Tsú-thuàn
zoxide 這個軟體讓我們用簡短的縮寫跳轉到曾經去過的目錄
This is a smarter cd
command. When I do z xxx
, it would bring me to the most frequently used directory with "xxx" in the name. More you use it, it would get more accurated.
Atuin [software-000Q]
- December 15, 2023
- Lîm Tsú-thuàn
- https://atuin.sh
Atuin [software-000Q]
- December 15, 2023
- Lîm Tsú-thuàn
- https://atuin.sh
atuin 紀錄 CLI history,互動操作更方便而且可以跨電腦同步指令
atuin
gives better interactive interface to do command history search, once you found a target, use
-
<tab>
to back to shell and edit the command; and -
<enter>
to execute the command directly.
There is a post teach you to use self hosted sync server.
Sd [software-000T]
- December 31, 2023
- Lîm Tsú-thuàn
- https://github.com/chmln/sd
Sd [software-000T]
- December 31, 2023
- Lîm Tsú-thuàn
- https://github.com/chmln/sd
sd
替換sed
指令
Intuitive find & replace CLI (sed alternative).
Ast-grep [software-000V]
- December 31, 2023
- Lîm Tsú-thuàn
- https://ast-grep.github.io/
- https://github.com/ast-grep/ast-grep
Ast-grep [software-000V]
- December 31, 2023
- Lîm Tsú-thuàn
- https://ast-grep.github.io/
- https://github.com/ast-grep/ast-grep
sg
指令用語法而不是文字搜尋,對程式碼進行搜尋的效果會更好
A CLI tool for code structural search, lint and rewriting.
Croc [software-000P]
- December 15, 2023
- https://github.com/schollz/croc
Croc [software-000P]
- December 15, 2023
- https://github.com/schollz/croc
The tool send files from one computer to another securely.
croc 可以處理像是 keys 遷移這類問題
Migrate gpg keys to new machine [software-000O]
- December 15, 2023
- Lîm Tsú-thuàn
Migrate gpg keys to new machine [software-000O]
- December 15, 2023
- Lîm Tsú-thuàn
gpg -a --export > publickeys.asc gpg -a --export-secret-keys > privatekeys.asc gpg --export-ownertrust > trust.txt
Then use tools e.g. croc to transfer files. Apply below commands in new machine
gpg --import publickeys.asc gpg --import privatekeys.asc gpg -K gpg -k gpg --import-ownertrust trust.txt
Now your gpg is migrated.
為什麼需要 domain theory?遞迴的數學表示 [math-003Z]
- December 9, 2023
- Lîm Tsú-thuàn
為什麼需要 domain theory?遞迴的數學表示 [math-003Z]
- December 9, 2023
- Lîm Tsú-thuàn
一般的 OCaml 函數可以寫成
let f x y z = ...
一個直覺的想法是:每個型別都解釋成一個可數集合,該型別的 term 解釋成這個集合的元素。但有些函數會用到自己本身,例如整數階乘函數
let rec fac n = if n = 0 then 1 else n * fac(n-1)
它的值是什麼呢?答案是
\[ \mu (x : int \to int). \lambda (n : int). \begin {aligned} \begin {cases} 1 &\quad &(n = 0) \\ n \times x(n-1) &\quad &(n \ne 0) \end {cases} \end {aligned} \]\(\mu \) 中的 \(x\) 就是 fac
自己,把原始 OCaml 程式中的 fac
換成 \(x\) 即可。問題是集合論沒有辦法充分解釋這個運算,具體來說,集合解釋不滿足 PCF 的 Adequacy theorem。
Theorem. Adequacy (充分性定理) [math-0044]
- December 9, 2023
- Lîm Tsú-thuàn
Theorem. Adequacy (充分性定理) [math-0044]
- December 9, 2023
- Lîm Tsú-thuàn
If \(M\) is closed term of ground type and \(\mathcal {C}\llbracket M \rrbracket = \mathcal {C}\llbracket V \rrbracket \) for a value \(V\), then \(M \Downarrow V\).
對一個形式系統來說,一個 model 需要證明自己能充分的表現系統的特徵,所以才需要證明這個定理。
一般來說,只考慮構造與操作規則的話,可以記成下面這樣
Definition. Rules of \(\mu \) [math-0040]
- December 9, 2023
- Lîm Tsú-thuàn
Definition. Rules of \(\mu \) [math-0040]
- December 9, 2023
- Lîm Tsú-thuàn
Typing [#251]
- December 9, 2023
- Lîm Tsú-thuàn
Typing [#251]
- December 9, 2023
- Lîm Tsú-thuàn
Operational (Big step) [#252]
- December 9, 2023
- Lîm Tsú-thuàn
Operational (Big step) [#252]
- December 9, 2023
- Lîm Tsú-thuàn
但我們想要知道在數學上可以用什麼物件表示運算子 \(\mu \),也就是指稱語意 (denotational semantic),我先定義一個這個目標需要達成的等式。
基本的約束 [math-0041]
- December 9, 2023
- Lîm Tsú-thuàn
基本的約束 [math-0041]
- December 9, 2023
- Lîm Tsú-thuàn
解釋 (interpretation)
\[\llbracket \Gamma \triangleright \mu (x:t). M : t \rrbracket \rho \]必須是一個能滿足下面等式的 \(\llbracket t \rrbracket \) 元素 \(d\)
\[d = \llbracket \Gamma , x:t \triangleright M : t \rrbracket (\rho [x \mapsto d])\]註:\(\rho \) 在後面講到語意解釋時會定義
問題是我們怎麼知道存在這麼一個元素呢?由於不動點定理,使得我們有動機把 \(\llbracket t \rrbracket \) 解釋成 cpo,把計算解釋成 monotone function 再套用不動點定理。從而得到一個合理的定義:least fixed point 即是 \(\mu \) 的表示物件。
Definition. \(\mathcal {C}\llbracket e \rrbracket \) 的解釋 [math-0043]
- December 9, 2023
- Lîm Tsú-thuàn
Definition. \(\mathcal {C}\llbracket e \rrbracket \) 的解釋 [math-0043]
- December 9, 2023
- Lîm Tsú-thuàn
Notation. [#589]
- December 9, 2023
- Lîm Tsú-thuàn
Notation. [#589]
- December 9, 2023
- Lîm Tsú-thuàn
這裡採用 \(x \mapsto v\) 表示數學中的函數,\(x\) 是輸入 \(v\) 是輸出;但 \(\rho [x \mapsto d]\) 則是指 \(\rho \) 中的 \(x\) 被替換成 \(d\)
在開始之前我們需要大概了解 \(\mathcal {C}\llbracket x \rrbracket \) 這個解釋的定義。
- 當 \(t\) 是型別,則 \(\mathcal {C}\llbracket t \rrbracket \) 是一個 cpo
- 當 \(s, t\) 是型別,則 \(\mathcal {C}\llbracket s \to t \rrbracket \) 是一個連續函數,domain 是 \(\mathcal {C}\llbracket s \rrbracket \) 而 codomain 是 \(\mathcal {C}\llbracket t \rrbracket \)
- \(\rho \) 是一個 \(\Gamma \)-環境,幫每個 \(\Gamma \) 中的變數 \(x\) 定義一個 \(\rho (x) \in \mathcal {C}\llbracket \Gamma (x) \rrbracket \),\(\Gamma (x)\) 是一個型別
- \(\mathcal {C}\llbracket \Gamma \triangleright M : t \rrbracket \rho \in \mathcal {C}\llbracket t \rrbracket \),要解釋成三種情形
- \(\mathcal {C}\llbracket \Gamma \triangleright x : t \rrbracket \rho = \rho (x)\)
需要 \(\rho \) 函數的部分,當我們在程式語言中寫下
let f : T = M
時,就在 \(\rho \) 這個部分函數中加入了 \(f = M\) 的定義,注意到 \(\rho \) 是部分函數,因為也可能被問到未綁定的變數 \(z\),這時候 \(\rho (z) = \bot \) - \( \mathcal {C}\llbracket \Gamma \triangleright \lambda (x : s). M : s \to t \rrbracket \rho = (d \mapsto \mathcal {C}\llbracket \Gamma , x : s \triangleright M : t \rrbracket (\rho [x \mapsto d])) \)
把程式函數包裝成數學函數
- \( \mathcal {C}\llbracket \Gamma \triangleright M(N) : t \rrbracket \rho = (\mathcal {C}\llbracket \Gamma \triangleright M : s \to t \rrbracket \rho )(\mathcal {C}\llbracket \Gamma \triangleright N : s \rrbracket \rho ) \)
直接利用作為解釋的數學函數進行調用
- \(\mathcal {C}\llbracket \Gamma \triangleright x : t \rrbracket \rho = \rho (x)\)
Definition. \(\mu \) 的解釋結果 [math-0042]
- December 9, 2023
- Lîm Tsú-thuàn
Definition. \(\mu \) 的解釋結果 [math-0042]
- December 9, 2023
- Lîm Tsú-thuàn
\(\mu \) 本身的公式倒沒有很複雜
\[ \mathcal {C}\llbracket \Gamma \triangleright \mu (x:t). M : t \rrbracket \rho = \text {fix}(f) \]其中數學函數 \(f\) 是
\[ d \mapsto \mathcal {C}\llbracket \Gamma , x : t \triangleright M : t \rrbracket \rho [x \mapsto d] \]但我們怎麼確認 \(\text {fix}(f)\) 的存在?我們已經知道 \(\mathcal {C}\llbracket t \rrbracket \) 是 cpo。根據不動點定理我們知道只要再證明 \(f\) 是連續函數即可;接著根據下面的定理我們可以知道這能夠套用到任意來自 ground type 的 functional 上
Proposition. (cpo)-continuous function space is a cpo [math-0047]
- December 10, 2023
Proposition. (cpo)-continuous function space is a cpo [math-0047]
- December 10, 2023
If \(D\) and \(E\) are cpo, then the continuous function space
\[ [D \to E] = \{ f : D \to E \mid f \ \text {is continuous} \}\]is a cpo under the pointwise order.
再來就可以選擇 least fixed point 作為 \(\text {fix}(f)\) 的解釋
\[\bigsqcup _{n \in \omega }d_n\]其中
- \(d_0 = \bot _{\llbracket t \rrbracket }\)
- \(d_n = \mathcal {C}\llbracket \Gamma , x : t \triangleright M : t \rrbracket \rho [x \mapsto d_{n-1}]\)
不過這條鏈 \(d_n\) 不需要是唯一的,只要對任何一條都能這樣推理即可。
要證明函數 \(d \mapsto \mathcal {C}\llbracket \Gamma , x : t \triangleright M : t \rrbracket \rho [x \mapsto d]\) 對所有 \(\Gamma \)-環境 \(\rho \) 都成立有點麻煩,需要歸納所有的語法構造,所以這裡就跳過。或許哪天我會寫這部分,不過有興趣的讀者可以先參考 Gunter 的書的第四章,或是自己根據 PCF 這個 metalanguage 進行證明。Sterling 的演講 Synthetic Domains in the 21st Century 也是很好的資源。
Create quiver service with local k8s and docker compose [k8s-0001]
- December 4, 2023
- Lîm Tsú-thuàn
Create quiver service with local k8s and docker compose [k8s-0001]
- December 4, 2023
- Lîm Tsú-thuàn
quiver is a modern commutative diagram editor, and also is a proper small service to show what can we do with local k8s.
Notice that I do these with OrbStack, you will need to do proper modification to work on your computer, so this is not in introduction level.
As OrbStack's document, every running service can be connected via domain *.k8s.orb.local
. So here we are going to create docker image for quiver.
Create docker image for quiver [docker-0001]
- December 4, 2023
- Lîm Tsú-thuàn
Create docker image for quiver [docker-0001]
- December 4, 2023
- Lîm Tsú-thuàn
First, you clone quiver repository into the current directory, then write down Dockerfile
FROM python:3.11.2-slim-buster WORKDIR /app COPY quiver/src /app COPY app.py /app CMD [ "python3", "app.py" ]
The app.py
import http.server import socketserver PORT = 8000 handler = http.server.SimpleHTTPRequestHandler with socketserver.TCPServer(("", PORT), handler) as httpd: print("Server started at localhost:" + str(PORT)) httpd.serve_forever()
Then use command docker build . -t quiver-quiver:latest
to create a docker image.
Pod and service configuration [k8s-0002]
- December 4, 2023
- Lîm Tsú-thuàn
Pod and service configuration [k8s-0002]
- December 4, 2023
- Lîm Tsú-thuàn
Now, we need configuration for pod and service.
apiVersion: v1 kind: Pod metadata: name: quiver labels: app: quiver spec: containers: - name: quiver image: quiver-quiver:latest imagePullPolicy: Never ports: - containerPort: 8000 name: http-web-svc --- apiVersion: v1 kind: Service metadata: name: quiver-service spec: selector: app: quiver ports: - protocol: TCP port: 80 targetPort: http-web-svc type: LoadBalancer
We use they via command kubectl apply -f ./quiver.yml
.
Finally, you can go to http://k8s.orb.local and see you already run quiver tool on local machine. Other way is using traefik with docker compose, and goes to http://quiver.localhost.
使用 traefik 代理 [docker-0002]
- January 25, 2024
- Lîm Tsú-thuàn
使用 traefik 代理 [docker-0002]
- January 25, 2024
- Lîm Tsú-thuàn
在 docker compose 檔案的 services
底下加入下列的代理服務設定
traefik: image: "traefik:v2.10" container_name: "traefik" command: - "--api.insecure=true" - "--providers.docker=true" - "--providers.docker.exposedbydefault=false" - "--entrypoints.web.address=:80" ports: - "80:80" # Web UI - "8080:8080" volumes: - "/var/run/docker.sock:/var/run/docker.sock:ro"
並在實際的服務容器下加入 label 控制 traefik 的動作,就可以指定 DNS 域名了
labels: - "traefik.enable=true" - "traefik.http.routers.whoami.rule=Host(`xxx.localhost`)" - "traefik.http.routers.whoami.entrypoints=web"
Forester 介紹 [forester-0002]
- December 2, 2023
- Lîm Tsú-thuàn
Forester 介紹 [forester-0002]
- December 2, 2023
- Lîm Tsú-thuàn
又是新的筆記軟體?是要換幾種? [forester-0003]
- December 2, 2023
- Lîm Tsú-thuàn
又是新的筆記軟體?是要換幾種? [forester-0003]
- December 2, 2023
- Lîm Tsú-thuàn
市面上有越來越多的筆記軟體,而擁有發佈功能的也不少,也就是說當你寫好筆記時,就可以選擇是否要公開,這種方式非常好用,而且也不再需要擔心文章不能寫一半,這種模式下你的文章會隨著累積而自然組合出新的想法/成果。 在使用 Heptabase 一定時間之後,我對它也相當滿意,但隨著使用,我對能夠掌控細節的需要又開始出現,下面舉出我遇到的問題,以及未來的需求規劃,最終會談到如何在 forester 中實現。
我們需要已完成的軟體 [software-000L]
- December 2, 2023
- Lîm Tsú-thuàn
- https://josem.co/the-beauty-of-finished-software/
我們需要已完成的軟體 [software-000L]
- December 2, 2023
- Lîm Tsú-thuàn
- https://josem.co/the-beauty-of-finished-software/
已完成的軟體這種概念,是指一個軟體的功能已經沒有大幅度更動的必要,可以長期使用在產品上,而軟體本身只會進行必要的安全與移植性更新
外部連結是我讀到這個想法的地方對應到筆記軟體上,我不希望軟體一直更新,尤其是當我一打開工具需要寫筆記時,上面的更新按鈕非常的讓人煩躁。同時,這個想法也是一種解放我們原先對軟體想像的開端,比起軟體如何如何,更重要的是真的去做,外部連結裡面也談到冰與火之歌正是用這樣的軟體寫出。更多的想法可以參考公共程式與洪朝貴老師的盲人摸象看軟體。
白板只適合學習,不適合專家 [noting-0001]
- December 2, 2023
- Lîm Tsú-thuàn
白板只適合學習,不適合專家 [noting-0001]
- December 2, 2023
- Lîm Tsú-thuàn
白板在剛開始學習一個領域或是開發一個專案的時候非常的好用,但隨著技能與專案開始複雜化,白板的資訊就只是過多的無用資訊了。下圖是我的教學專案,一點編譯器入門就已經膨脹到這個程度,維護範疇論的白板經驗告訴我這是不可行的。當然,我知道白板的用途不是如此,問題是如果白板只是一種聯想用、暫時性的存在,那為何不直接用紙筆呢?
一個筆記軟體應該做到什麼? [noting-0002]
- December 2, 2023
- Lîm Tsú-thuàn
一個筆記軟體應該做到什麼? [noting-0002]
- December 2, 2023
- Lîm Tsú-thuàn
一個好的筆記軟體應該要能夠
- 可以隨手記錄雜散的想法,所以要有手機版本
- 只讓成熟的想法公開,所以需要廢紙簍,在改寫之後才移到公開區
- 核心的概念已完成
下面我們就來談,forester 滿足與不滿足哪些要件。
Forester 的特性 [forester-0004]
- December 2, 2023
- Lîm Tsú-thuàn
Forester 的特性 [forester-0004]
- December 2, 2023
- Lîm Tsú-thuàn
forester 是一個精簡、hack 的工具,也就是說目前尚未有穩定的結果,我已經經歷過幾次大規模的更動,萬幸的是
- forester 是開源工具,你可以選擇停留在某個版本不再跟上,或是基於任何一點自行維護後續
- 目前的更動都是為了更符合核心理念,而不是為了增加非必要的功能
Forester 的不完美之處 [forester-0008]
- December 2, 2023
- Lîm Tsú-thuàn
Forester 的不完美之處 [forester-0008]
- December 2, 2023
- Lîm Tsú-thuàn
正如前面所說,forester 的更新是為了更符合核心想法,所以在已完成這點上,是合格的。除此之外,forester 可以使用
\tex{\latex-preamble/xxx}{...}
來使用任何你有興趣的 xxx.sty
(把 .sty
原始碼封裝到變數 \latex-preamble/xxx
中),因此生態成熟度相當高(latex 生態系),這點的直接成果就是可以使用 tikz 繪圖工具,下面是兩個案例。
Example. Category of span [math-001W]
- October 28, 2023
- Lîm Tsú-thuàn
Example. Category of span [math-001W]
- October 28, 2023
- Lîm Tsú-thuàn
A span is a \(\mathcal {C}\)-diagram \(A \leftarrow C \rightarrow B\), there is a category of span with fixed \(\mathbb {C}\)-objects \(A, B\) is:
- objects: \(A \leftarrow C \rightarrow B\)
- morphisms: given by the below diagram, the red-colored morphism \(h\)
Example. Monad [math-00D8]
- September 5, 2024
- Lîm Tsú-thuàn
Example. Monad [math-00D8]
- September 5, 2024
- Lîm Tsú-thuàn
monad 是一個 endofunctor,所以必然跟某個範疇 \(C\) 有關,具有 \(M : C \to C\) 的簽名。並且,有兩個 natural transformation
- \(\eta : 1_C \to M\)
- \(\mu : M \circ M \to M\)
並滿足 monoid 條件。第一是 \(\mu \cdot (\eta \circ M) = id = \mu \cdot (M \circ \eta )\)
第二是 \(\mu \cdot (\mu \circ M) = \mu \cdot (M \circ \mu )\)
因此我們才說 monad 是 endofunctors 構成的 category 中的一個 monoid object。
此外 RSS 是每個頁面都會有一個。在學術上,forester 也有針對 reference 的卡片分類,這裡引入一張卡片展示這個功能:
Example. Elements of ∞-Category Theory [riehl-verity2022]
- 2022
- Emily Riehl, Dominic Verity
- 10.1017/9781108936880
Example. Elements of ∞-Category Theory [riehl-verity2022]
- 2022
- Emily Riehl, Dominic Verity
- 10.1017/9781108936880
The language of ∞-categories provides an insightful new way of expressing many results in higher-dimensional mathematics but can be challenging for the uninitiated. To explain what exactly an ∞-category is requires various technical models, raising the question of how they might be compared. To overcome this, a model-independent approach is desired, so that theorems proven with any model would apply to them all. This text develops the theory of ∞-categories from first principles in a model-independent fashion using the axiomatic framework of an ∞-cosmos, the universe in which ∞-categories live as objects. An ∞-cosmos is a fertile setting for the formal category theory of ∞-categories, and in this way the foundational proofs in ∞-category theory closely resemble the classical foundations of ordinary category theory. Equipped with exercises and appendices with background material, this first introduction is meant for students and researchers who have a strong foundation in classical 1-category theory.
@book{riehl_verity_2022, place={Cambridge}, series={Cambridge Studies in Advanced Mathematics}, title={Elements of ∞-Category Theory}, DOI={10.1017/9781108936880}, publisher={Cambridge University Press}, author={Riehl, Emily and Verity, Dominic}, year={2022}, collection={Cambridge Studies in Advanced Mathematics} }
怎麼安裝 forester? [forester-0005]
- December 2, 2023
- Lîm Tsú-thuàn
怎麼安裝 forester? [forester-0005]
- December 2, 2023
- Lîm Tsú-thuàn
我個人使用的安裝方式是從原始碼編譯(用 nix 管理),因為我會參與開發跟使用最新功能,但這個辦法對沒有那麼想折騰的人來說可能不是那麼理想,這時候可以選擇用 opam install forester
直接使用 opam 上註冊的最新版本。如果你也想要直接用原始碼的話,那麼進入專案之後執行 opam pin add -y .
即可,往後更新只需要執行下列的指令就可以完成。
git pull opam update opam upgrade
此外 changelog 頁面也值得關注,具體的概念跟使用應該去這邊學習。如果你熟悉 nix 的話也可以用我做的 template 專案當起點。
記錄專案歷程的案例 [forester-0006]
- December 2, 2023
- Lîm Tsú-thuàn
記錄專案歷程的案例 [forester-0006]
- December 2, 2023
- Lîm Tsú-thuàn
forester 具有很強的自由度,這也是我寫這段的理由:展示用法的多樣化。我這裡所談的管理方式或許對你來說沒有必要,這是我為什麼現在才談這件事。在我目前對筆記軟體使用上的最後一哩路是專案時程紀錄,因為一個大型的專案會涉及到長期追蹤,在時程安排上,我目前使用的是 orgmode 跟 Heptabase。由於提醒事項這個功能 forester 沒有也不會提供這類功能,所以我不會討論這部分,而且也不需要,我未來會只用 orgmode 紀錄警急需求,而專案則記錄在 forester 上。因此,這裡要談個人專案管理需要什麼。由於 forester 也有 backlink,因此我們可以考慮在每日頁面裡面提及某個事項,比如軟體專案中的某個功能是在這一日進行。並且在專案中建立兩個 scope transclude
\scope{ \put\transclude/title{working} \put\transclude/expanded{true} \query{ \open\query \isect{\tag{project-xxx}}{\tag{TODO}} } } \scope{ \put\transclude/title{complete} \put\transclude/expanded{true} \query{ \open\query \isect{\tag{project-xxx}}{\tag{DONE}} } }
上面的 scope transclude 表示當有 project-xxx
與 TODO
這兩個 tag 時視為事項正在進行,下面表示事項已完成。而我只會在 DONE
的事項上面指定日期,因此我就知道是哪一天完成。但這也有一些缺點,比如我可能需要知道事項是什麼時候開始的,由於 forester 格式開放,因此我可以自行加上我需要的特殊閱讀工具,所以這些也是我在思考要怎麼加入 forester 或是有什麼額外工具可以做到的部分,因此在未來我或許可以談更多關於工作紀錄管理的細節,不過這一段就先到這裡吧。
Conclusion. 如何找到合適的工具 [forester-0007]
- December 2, 2023
- Lîm Tsú-thuàn
Conclusion. 如何找到合適的工具 [forester-0007]
- December 2, 2023
- Lîm Tsú-thuàn
我同意除了 latex 的超優秀支援,其他很多功能都是封閉軟體如我所使用的 Heptabase 可以做到的,所以結論要談為什麼這還是有嘗試的價值。
- forester 是開源的,這表示你有很多選擇:分叉做新的功能、回饋給維護者並知道開發進展、自己選什麼時候要更新
- 它按照相當精簡的規則運作,也就是說學習整套規則並不困難,並且相對容易判斷操作的結果
但在下判斷之前,也要了解到我是使用者也參與開發,所以我的判斷可能過於樂觀。因此我也推薦讀者要學習觀念而不是工具,並也考慮另一個或許不錯的替代品 AFFiNE。最後,就如在已完成中所述,你要真的有在寫筆記,這一切才會對你有意義。
如果有興趣使用,可以參照這篇教學來了解怎麼開始。
Definition. Boolean algebra [math-003I]
- November 29, 2023
- Lîm Tsú-thuàn
Definition. Boolean algebra [math-003I]
- November 29, 2023
- Lîm Tsú-thuàn
A Boolean algebra is a complemented distributive lattice.
Proposition. \({x^\mathsf {c}}^\mathsf {c} = x\) [math-003L]
- November 29, 2023
- Lîm Tsú-thuàn
Proposition. \({x^\mathsf {c}}^\mathsf {c} = x\) [math-003L]
- November 29, 2023
- Lîm Tsú-thuàn
In boolean algebra, the complement of complement of \(x\) is \(x\).
Proof. [#595]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#595]
- November 29, 2023
- Lîm Tsú-thuàn
This is a direct result from at most one complement.
Proposition. \(x \sqcap y = 0\) if and only if \(y \sqsubseteq x^{\mathsf {c}}\) [math-003M]
- November 29, 2023
- Lîm Tsú-thuàn
Proposition. \(x \sqcap y = 0\) if and only if \(y \sqsubseteq x^{\mathsf {c}}\) [math-003M]
- November 29, 2023
- Lîm Tsú-thuàn
In boolean algebra, the problem can be expressed categorical: \(x \times y = 0\) iff \(y \to x^{\mathsf {c}}\).
Proof. [#594]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#594]
- November 29, 2023
- Lîm Tsú-thuàn
We have product \(x \leftarrow 0 \rightarrow y\), and the \(y \to 1\) (terminal rule), but complement \(x^\mathsf {c}\) existed and \(x + y\) has no need to be \(1\), so somewhere between \(y \to 1\) has a \(x^\mathsf {c}\).
Proposition. \(x \sqsubseteq y\) if and only if \(y^\mathsf {c} \sqsubseteq x^\mathsf {c}\) [math-003N]
- November 29, 2023
- Lîm Tsú-thuàn
Proposition. \(x \sqsubseteq y\) if and only if \(y^\mathsf {c} \sqsubseteq x^\mathsf {c}\) [math-003N]
- November 29, 2023
- Lîm Tsú-thuàn
In boolean algebra, the problem can be expressed categorical: \(x \to y\) iff \(y^\mathsf {c} \to x^\mathsf {c}\).
Proof. [#593]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#593]
- November 29, 2023
- Lîm Tsú-thuàn
By applying proposition: \(x \sqcap y = 0\) iff \(y \sqsubseteq x^{\mathsf {c}}\), with fact that \(x \to y\), we know \(y^\mathsf {c} \sqcap x = 0\)
Apply proposition again, we can see the goal existed.
Proposition. \((x \sqcap y)^\mathsf {c} = x^\mathsf {c} \sqcup y^\mathsf {c}\) [math-003O]
- November 29, 2023
- Lîm Tsú-thuàn
Proposition. \((x \sqcap y)^\mathsf {c} = x^\mathsf {c} \sqcup y^\mathsf {c}\) [math-003O]
- November 29, 2023
- Lîm Tsú-thuàn
In boolean algebra, we can rewrite it categorical: \((x \times y)^\mathsf {c} = x^\mathsf {c} + y^\mathsf {c}\).
Proof. [#592]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#592]
- November 29, 2023
- Lîm Tsú-thuàn
By removing the thing we no need, we can see that \((x \times y)^\mathsf {c} = x^\mathsf {c} + y^\mathsf {c}\).
Proposition. \((x \sqcup y)^\mathsf {c} = x^\mathsf {c} \sqcap y^\mathsf {c}\) [math-003P]
- November 29, 2023
- Lîm Tsú-thuàn
Proposition. \((x \sqcup y)^\mathsf {c} = x^\mathsf {c} \sqcap y^\mathsf {c}\) [math-003P]
- November 29, 2023
- Lîm Tsú-thuàn
In boolean algebra, we can rewrite in categorical language: \((x + y)^\mathsf {c} = x^\mathsf {c} \times y^\mathsf {c}\).
Proof. [#591]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#591]
- November 29, 2023
- Lîm Tsú-thuàn
Indexing boolean algebra [math-003J]
- February 16, 2022
- Lîm Tsú-thuàn
Indexing boolean algebra [math-003J]
- February 16, 2022
- Lîm Tsú-thuàn
Boolean algebra can be encoded by indexing, for example, a venn diagram for two sets \(A, B\) divide diagram to four parts: \(1, 2, 3, 4\). Thus
- \(A = \{1, 2\}\)
- \(B = \{1, 3\}\)
- \(A \cup B = \{1, 2, 3\}\)
- \(A \cap B = \{1\}\)
- \((A \cup B)^{\mathsf {c}} = \{4\}\)
The benefit of the encoding is the encoding let any sets can be treated as finite sets operation. So for any set check a boolean algebra is valid, indexing helps you check them by computer.
Encode to program [cs-000J]
- February 16, 2022
- Lîm Tsú-thuàn
Encode to program [cs-000J]
- February 16, 2022
- Lîm Tsú-thuàn
Here is the racket program.
(define I (set 1 2 3 4)) (define A (set 1 2)) (define B (set 1 3)) (define ∅ (set)) (define ∩ set-intersect) (define ∪ set-union) (define (not S) (set-subtract I S)) (define (→ A B) (∪ (not A) B)) (define (- A B) (∩ A (not B))) (define (≡ A B) (∪ (∩ A B) (∩ (not A) (not B))))
Checking based on encoding [cs-000K]
- February 16, 2022
- Lîm Tsú-thuàn
Checking based on encoding [cs-000K]
- February 16, 2022
- Lîm Tsú-thuàn
Now, you can check \(A \to B = (A - B)^{\mathsf {c}}\) by the following program.
(equal? (→ A B) (not (- A B)))
And you will know \((A \cap (A - B)^{\mathsf {c}}) = \emptyset \) is invalid since the following program returns false.
(equal? (∩ A (not (- A B))) ∅)
You can even extend this method for sets \(A, B, C\), for sets \(A, B, C, D\) and so on, but then that's too far for this article.
Theorem. Each element of distributive lattice has at most one complement [math-003K]
- November 29, 2023
- Lîm Tsú-thuàn
Theorem. Each element of distributive lattice has at most one complement [math-003K]
- November 29, 2023
- Lîm Tsú-thuàn
In a distributive lattice each element has at most one complement, which means \(y, z\) are complements of \(x\) implies \(y = z\).
Proof. [#596]
- November 29, 2023
- Lîm Tsú-thuàn
Proof. [#596]
- November 29, 2023
- Lîm Tsú-thuàn
The proof use category language, \(\sqcap \) (product) and \(\sqcup \) (coproduct).
Assuming there have two complements \(y, z\) for an element \(x\), then \(x + y = x + z = 1\) and \(x \times y = x \times z = 0\). By distributive law we have below diagram
Then we use \(x + y = x + z = 1\) to reduce it and get
Since there has at most one path, the diagram commute, hence \(y = z\).
Soundness 與 completeness [math-0032]
- November 27, 2023
- Lîm Tsú-thuàn
Soundness 與 completeness [math-0032]
- November 27, 2023
- Lîm Tsú-thuàn
為了了解 sound 與 complete 的比喻,我們需要觀察經典邏輯系統的 soundness 與 completeness 定理,因此我們先複習經典邏輯的公理與推導式
Definition. Classical logic [math-0035]
- November 27, 2023
- Lîm Tsú-thuàn
Definition. Classical logic [math-0035]
- November 27, 2023
- Lîm Tsú-thuàn
The twelve forms, where \(\alpha , \beta , \gamma \) denotes arbitrary sentences, are axioms of classical logic.
- \(\alpha \supset (\alpha \land \alpha )\)
- \((\alpha \land \beta ) \supset (\beta \land \alpha )\)
- \((\alpha \supset \beta ) \supset ((\alpha \land \gamma ) \supset (\beta \land \gamma ))\)
- \(((\alpha \supset \beta ) \land (\beta \supset \gamma )) \supset (\alpha \supset \gamma )\)
- \(\beta \supset (\alpha \supset \beta )\)
- \((\alpha \land (\alpha \supset \beta )) \supset \beta \)
- \(\alpha \supset (\alpha \lor \beta )\)
- \((\alpha \lor \beta ) \supset (\beta \lor \alpha )\)
- \(((\alpha \supset \gamma ) \land (\beta \supset \gamma )) \supset ((\alpha \lor \beta ) \supset \gamma )\)
- \(\sim \alpha \supset (\alpha \supset \beta )\)
- \(((\alpha \supset \beta ) \land (\alpha \supset \sim \beta )) \supset \sim \alpha \)
- \(\alpha \lor \sim \alpha \)
with single rule of inference.
Rule of Detachment [#247]
- November 27, 2023
- Lîm Tsú-thuàn
Rule of Detachment [#247]
- November 27, 2023
- Lîm Tsú-thuàn
From \(\alpha \) and \(\alpha \supset \beta \), the sentence \(\beta \) may be derived. Denote derivable formula \(\vdash _{cl} \alpha \), we can rewrite rule of detachment to \[ \frac { \vdash _{cl} \alpha \ \ \ \ \vdash _{cl} (\alpha \supset \beta ) }{ \vdash _{cl} \beta } \]
有了推導規則 Rule of Detachment,經典邏輯系統的 soundness 與 completeness 定理表示
Theorem. Classical logic's soundness [math-0033]
- November 27, 2023
- Lîm Tsú-thuàn
Theorem. Classical logic's soundness [math-0033]
- November 27, 2023
- Lîm Tsú-thuàn
If \(\vdash _{cl} \alpha \), then \(\alpha \) is classically valid.
Theorem. Classical logic's completeness [math-0034]
- November 27, 2023
- Lîm Tsú-thuàn
Theorem. Classical logic's completeness [math-0034]
- November 27, 2023
- Lîm Tsú-thuàn
If \(\alpha \) is classically valid, then \(\vdash _{cl} \alpha \).
這兩個定理也因此可以推廣到更多的系統中,比如靜態分析中的比喻
Example. 靜態分析中的 sound 與 complete [cs-000I]
- November 27, 2023
- Lîm Tsú-thuàn
Example. 靜態分析中的 sound 與 complete [cs-000I]
- November 27, 2023
- Lîm Tsú-thuàn
若是將比喻套進靜態分析中,便可以發現 sound 是「發現的錯誤都是真的」,也就是系統不會誤報;而 complete 則表示「所有的錯誤都會被系統找到」,也就是不會遺漏錯誤。但要記得這兩者在靜態分析中通常無法同時達成,而且兩者的極端都會產生沒用的系統。比如對所有程式都會檢測出錯誤那絕對有滿足 complete,但也肯定是沒用的系統;而滿足 sound 的系統則往往透露太少錯誤,而且這類錯誤通常開發人員也很容易自己發現,因此也不實用。因此靜態分析與證明系統發展上的差異,就是靜態分析需要在 sound 跟 complete 這些屬性裡面取得平衡。
Conclusion. 如何使用 soundness 與 completeness [math-0036]
- November 27, 2023
- Lîm Tsú-thuàn
Conclusion. 如何使用 soundness 與 completeness [math-0036]
- November 27, 2023
- Lîm Tsú-thuàn
因此可以發現,要用 soundness 與 completeness 時,只要關心特定屬性 \(p\),我們說一個系統 sound 就是在問「能導出的結果是否滿足 \(p\)」;我們說一個系統 complete 則是在問「滿足 \(p\) 的結果是否皆能導出」。
Theorem. A space is Hausdorff iff its diagonal map is closed [math-002Z]
- November 23, 2023
- Lîm Tsú-thuàn
Theorem. A space is Hausdorff iff its diagonal map is closed [math-002Z]
- November 23, 2023
- Lîm Tsú-thuàn
The proposition says a space is Hausdorff if and only if its diagonal map \(\Delta : X \to X \times X\) to product space is closed, which given an alternative definition. Notice that close means its complement \(\Delta ^\mathsf {c}\) is open. The definition of \(\Delta \) is
\[ \Delta = \{ (x, x) \mid x \in X \} \]
Remark. [#603]
- November 23, 2023
- Lîm Tsú-thuàn
Remark. [#603]
- November 23, 2023
- Lîm Tsú-thuàn
Not hard to see below argument also applies to all finite \(X\)-product spaces.
Proof. [#604]
- November 23, 2023
- Lîm Tsú-thuàn
Proof. [#604]
- November 23, 2023
- Lîm Tsú-thuàn
The first direction is Hausdorff implies diagonal map is closed. Hausdorff means every two different points has a pair of disjoint neighborhoods \((U \in \mathcal {N}_x, V \in \mathcal {N}_y)\), where \(x \in U\) and \(y \in V\). therefore, every pair \((x, y)\) not line on the diagonal has \(U \times V\) cover them. The union of all these open sets \(U \times V\) indeed covers \(\Delta ^\mathsf {c}\), so the complement \(\Delta \) is closed.
The second direction is diagonal map is closed implies Hausdorff. Since
\[\Delta ^\mathsf {c} = \{(x, y) \mid x, y \in X (x \ne y) \}\]is open, which implies for all \(x, y\) the pair \((x, y) \in \Delta ^\mathsf {c}\). Since \(\mathcal {N}_{(x, y)} = \mathcal {N}_x \times \mathcal {N}_y\), this implies the fact that \(\Delta ^\mathsf {c} \in \mathcal {N}_x \times \mathcal {N}_y\).
Also, for all \(U \in \mathcal {N}_x\) and \(V \in \mathcal {N}_y\), it's natural that \(U \times V \subseteq \Delta ^\mathsf {c}\), since the open set \(U \times V\) at most cover \(\Delta ^\mathsf {c}\).
Consider that reversely again, that means for all \((x, x) \in \Delta \), pair \((x, x) \notin U \times V\) (i.e. \(U \times V\) will not cover any part of diagonal), that implies \(U \cap V = \varnothing \) as desired.
Understanding \(F\)-algebra [math-001K]
- October 24, 2023
- Lîm Tsú-thuàn
Understanding \(F\)-algebra [math-001K]
- October 24, 2023
- Lîm Tsú-thuàn
To understand \(F\)-algebra, we will need some observations, the first one is we can summarize an algebra with a signature. For example, monoid has a signature:
\[ \begin {cases} 1 : 1 \to m \\ \cdot : m \times m \to m \end {cases} \]or we can say ring is:
\[ \begin {cases} 0 : 1 \to m \\ 1 : 1 \to m \\ + : m \times m \to m \\ \times : m \times m \to m \\ - : m \to m \end {cases} \]The next observation is we can consider these \(m\) as objects in a proper category \(C\), at here is a cartesian closed category. For example
- monoid is a \(C\)-morphism \(1 + m \times m \to m\)
- ring is a \(C\)-morphism \(1 + 1 + m \times m + m \times m + m \to m\)
Now, we generalize algebra's definition.
Definition. \(F\)-algebra (algebra for an endofunctor) [math-001L]
- October 24, 2023
- Lîm Tsú-thuàn
Definition. \(F\)-algebra (algebra for an endofunctor) [math-001L]
- October 24, 2023
- Lîm Tsú-thuàn
With a proper category \(C\) which can encode the signature of \(F(-)\), and an endofunctor \(F : C \to C\), the \(F\)-algebra is a triple: \[(F, x, \alpha )\] where \(\alpha : F \; x \to x\) is a \(C\)-morphism.
With the definition of \(F\)-algebra, we wondering if \(F\)-algebras of a fixed \(F\) form a category, and the answer is yes.
Definition. Category of \(F\)-algebras [math-001M]
- October 24, 2023
- Lîm Tsú-thuàn
Definition. Category of \(F\)-algebras [math-001M]
- October 24, 2023
- Lîm Tsú-thuàn
For a fixed endofunctor \(F\) in a proper category \(C\) (below notations omit fixed \(F\)),
- the F-algebras \((x, \alpha )\) form the objects of the category,
- morphisms are homomorphisms of objects \((x, \alpha ) \xrightarrow {F\;m} (y, \beta )\), composition is given by functor laws.
We can extra check identity indeed works.
There is a theorem about the initial object of the category.
Theorem. Lambek's [math-001N]
- October 24, 2023
- Lîm Tsú-thuàn
Theorem. Lambek's [math-001N]
- October 24, 2023
- Lîm Tsú-thuàn
The evaluator \(j\) of an initial algebra \((F, i, j)\) is an isomorphism.
Proof. [#617]
- October 24, 2023
- Lîm Tsú-thuàn
Proof. [#617]
- October 24, 2023
- Lîm Tsú-thuàn
Let \(F\;i\) be an initial in the \(F\)-algebra category, the following diagram commutes for any \(C\)-object \(a\)
Now, replace \(a\) with \(F\;i\), we have commute diagram
Then we consider a trivial commute diagram by duplicating the path \(F\;i \to i\)
Combine two diagrams, then we get another commute diagram
By definition now we know \(j \circ m\) is a homomorphism, and since \(F\;i\) is an initial, we must have \[F\;j \circ F\;m = 1_{Fi}\]
Therefore, we also have \[j \circ m = 1_i\] so \(m\) is the inverse of \(j\), proves \(j\) is an isomorphism.
Catamorphism [math-001P]
- October 24, 2023
- Lîm Tsú-thuàn
Catamorphism [math-001P]
- October 24, 2023
- Lîm Tsú-thuàn
The theorem actually proves the corresponding \(C\)-object \(i\) of initial algebra \((F, i, j)\) is a fixed point of \(F\). By reversing \(j\) with its inverse, we get a commute diagram below.
In Haskell, we are able to define initial algebra
newtype Fix f = Fix (f (Fix f)) unFix :: Fix f -> f (Fix f) unFix (Fix x) = x
View \(j\) as constructor Fix
, \(j^{-1}\) as unFix
, then we can define m = alg . fmap m . unFix
. Since m :: Fix f -> a
, we have definition of catamorphism.
cata :: Functor f => (f a -> a) -> Fix f -> a cata alg = alg . fmap (cata alg) . unFix
An usual example is foldr
, a convenient specialization of catamorphism.
Anamorphism [math-001Q]
- October 24, 2023
- Lîm Tsú-thuàn
Anamorphism [math-001Q]
- October 24, 2023
- Lîm Tsú-thuàn
As a dual concept, we can draw coalgebra diagram
and define anamorphism as well.
ana :: Functor f => (a -> f a) -> a -> Fix f ana coalg = Fix . fmap (ana coalg) . coalg
Conclusion. [#260]
- October 24, 2023
- Lîm Tsú-thuàn
Conclusion. [#260]
- October 24, 2023
- Lîm Tsú-thuàn
I mostly learn F-algebras from Category Theory for Programmers, and take a while to express the core idea in details with my voice with a lot practicing. The article answered some questions, but we always with more. What's an algebra of monad? What's an algebra of a programming language (usually has a recursive syntax tree)? Hope you also understand it well through the article and practicing.
什麼是 Lawvere's fixed point theorem [math-0012]
- October 11, 2023
- Lîm Tsú-thuàn
什麼是 Lawvere's fixed point theorem [math-0012]
- October 11, 2023
- Lîm Tsú-thuàn
這篇文章介紹了 Lawvere's fixed point theorem 的定義與應用
Theorem. Lawvere's fixed point [math-0013]
- October 11, 2023
- Lîm Tsú-thuàn
- http://tac.mta.ca/tac/reprints/articles/15/tr15.pdf
Theorem. Lawvere's fixed point [math-0013]
- October 11, 2023
- Lîm Tsú-thuàn
- http://tac.mta.ca/tac/reprints/articles/15/tr15.pdf
在一個 cartesian closed category 中,如果 \(A \xrightarrow {\phi } B^A\) 是 point-surjective,則所有 \(B \xrightarrow {f} B\) 都存在不動點 \(1 \xrightarrow {s} B\)(滿足 \(f \circ s = s\))。
Proof. [#626]
- October 11, 2023
- Lîm Tsú-thuàn
Proof. [#626]
- October 11, 2023
- Lîm Tsú-thuàn
首先畫出交換圖
其中 \(\delta \) 的定義是 \(c \mapsto \langle c, c \rangle \),所以對 \(1 \xrightarrow {p} A\) 來說 \(\delta \circ p = \langle p, p \rangle \)。沿著這個定義,我們知道 \((\phi \times 1_A) \circ \delta \circ p = \langle \phi \circ p, p\rangle \)。根據 point-surjective 我們知道 \(\phi \circ p\) 對每個 \(p\) 來說都是唯一確定的。現在把往下方 \(B\) 的 \(ev\) 也畫出,即可得出等式:
\[f \circ ev \circ \langle \phi \circ p, p\rangle = ev \circ \langle \phi \circ p, p\rangle \]換句話說 \(B \xrightarrow {f} B\) 的不動點即是
\[ev \circ \langle \phi \circ p, p\rangle \]
Example. 應用到 lambda calculus [math-001S]
- October 26, 2023
- Lîm Tsú-thuàn
Example. 應用到 lambda calculus [math-001S]
- October 26, 2023
- Lîm Tsú-thuàn
編碼的方式是找一個只有兩個物件 \(1, T\) 的 category \(M\),讓 lambda calculus 的 terms 是 \(M\)-morphisms,這些技巧在 categorical semantic 領域內相當常見。
到這裡必須檢查 lambda calculus 確實存在 point-surjective,歡迎自行嘗試。按此編碼後可以得到 \(ev \circ \langle \phi \circ p, p\rangle \xrightarrow {encode} \phi (p)(p)\)。套到等式上 \[f \circ ev \circ \langle \phi \circ p, p\rangle = ev \circ \langle \phi \circ p, p\rangle \] 可以得到以下編碼 \[f(\phi (p)(p)) = \phi (p)(p)\] 把 \(\phi (p)\) 改寫成 \(q\),於是等式可以寫成 \(q(p) = f(\phi (p)(p))\),而函數套用語法可以用 \(\lambda \) 退化,於是得到 \[q = \lambda x. f(\phi (x)(x))\]
注意到 \(q\) 的定義是非遞迴的,因此一定是可定義的。
計算即可發現確實 \(q(p) = \phi (p)(p) = f(\phi (p)(p))\)。因為所有的 \(\lambda \)-term 都屬於 \(T\),所以現在我們知道任何 lambda calculus 的函數都有不動點。
Example. 應用到 Cantor's theorem [math-0016]
- October 11, 2023
- Lîm Tsú-thuàn
Example. 應用到 Cantor's theorem [math-0016]
- October 11, 2023
- Lîm Tsú-thuàn
取 category \(\bold {Sets}\) 並令 \(B = 2\) 就可以證明 Cantor's theorem。我們需要引理
Lemma. No point-surjective morphism [math-0017]
- October 11, 2023
- Lîm Tsú-thuàn
Lemma. No point-surjective morphism [math-0017]
- October 11, 2023
- Lîm Tsú-thuàn
If there exists \(B \xrightarrow {f} B\) such that \(f \circ b \ne b\) for all \(1 \xrightarrow {b} B\), then there has no point-surjective morphism can exist for \(A \xrightarrow {g} B^A\).
This is a reversed version of Lawvere's fixed point theorem, no need an extra proof.
Proof. [#625]
- October 11, 2023
- Lîm Tsú-thuàn
Proof. [#625]
- October 11, 2023
- Lîm Tsú-thuàn
這個定理也可以用到 Gödel incompleteness、Tarski definability 等等問題上。論文 Substructural fixed-point theorems and the diagonal argument: theme and variations 更進一步的簡化了前置條件。
Understand comma category [math-000U]
- October 3, 2023
- Lîm Tsú-thuàn
Understand comma category [math-000U]
- October 3, 2023
- Lîm Tsú-thuàn
Comma category is generated by two functors, denoted \((T \downarrow S)\).
To understand the idea, we can start from slice & co-slice category, which is a special case of comma category. In co-slice category, we have objects \(\langle f, c \rangle \) where \(x \xrightarrow {f} c\), and morphism \(\langle f, c \rangle \xrightarrow {h} \langle f', c' \rangle \) where below diagram commutes:
We give another denotation \((x \downarrow C)\) for object \(x\) and its category \(C\) for this concept, and \((C \downarrow x)\) for the dual.
If we generalize the idea, by replacing category \(C\) with a functor \(S : D \to C\), then we get a category \((x \downarrow S)\) with
- objects \(\langle f, d \rangle \) where \(x \xrightarrow {f} Sd\)
- morphisms \(h : \langle f, d \rangle \to \langle f', d' \rangle \) where below diagram commutes:
If we replace object \(x\) to another functor \(T\)? It's the full picture of comma category:
Definition. Comma category [math-000V]
- October 3, 2023
- Lîm Tsú-thuàn
Definition. Comma category [math-000V]
- October 3, 2023
- Lîm Tsú-thuàn
Given categories and functors
The comma category \((T \downarrow S)\) (or \((T,S)\)) has
- objects \(\langle e,d,f \rangle \) where \(e \in E\), \(d \in D\), and \(T(e) \xrightarrow {f} S(d)\)
- morphisms \(\langle k,h \rangle : \langle e,d,f \rangle \to \langle e',d',f' \rangle \) where below commutes:
Example. Slice category as comma category [math-000W]
- October 3, 2023
- Lîm Tsú-thuàn
Example. Slice category as comma category [math-000W]
- October 3, 2023
- Lîm Tsú-thuàn
With the definition, now we can see how slice & co-slice category is a special case of comma category:
- Replace object \(x\) with a functor \(T : 1 \to C\), it will exactly pick a certain object, in case is \(x\)
- Replace functor \(S : D \to C\) with identity functor of \(C\), and hence, it's the category itself
Example. All morphisms of \(C\) [math-002K]
- October 3, 2023
- Lîm Tsú-thuàn
Example. All morphisms of \(C\) [math-002K]
- October 3, 2023
- Lîm Tsú-thuàn
Take \(T = S = 1_C\), then \((C \downarrow C)\) is \(C^2\) (all morphisms of \(C\))
子類型與多型(泛型) [tt-000F]
- September 23, 2023
- Lîm Tsú-thuàn
子類型與多型(泛型) [tt-000F]
- September 23, 2023
- Lîm Tsú-thuàn
這個文章源自下面的問題
不過想問問專業的⋯⋯Golang 都有 interface 這種東西,提供泛型的必要性是什麼啊?
這是個常見的誤解,因為大部分語言不會多認真跟你講清楚到底啥是啥,看來好像都能接受多種不同的類型輸入不是嗎?所以這裡我們就來看各種機制的定義跟差別。
Go 的 interface [tt-000D]
- September 23, 2023
- Lîm Tsú-thuàn
Go 的 interface [tt-000D]
- September 23, 2023
- Lîm Tsú-thuàn
Go 語言的 interface,範例如下
type Abser interface { Abs() float64 }
其中的 Abs() float64
可以被改寫成抽象語法 Abs : () -> float64
。因此一個 interface \(A\) 有一組與其關聯的一系列簽名 \(\hat P\)。並且,對 Go 而言下列的兩個 interface 並沒有差異
type A interface { F(C) D } type B interface { F(C) D }
因此我們可以更進一步認為 Go 的一個 interface \(A\) 可以完全由其簽名 \(\hat P\) 替換。
Java 的 interface 與 bounded polymorphism (bounded quantification) [tt-000E]
- September 23, 2023
- Lîm Tsú-thuàn
Java 的 interface 與 bounded polymorphism (bounded quantification) [tt-000E]
- September 23, 2023
- Lîm Tsú-thuàn
在 Java 之中可以定義 interface,範例如下
interface Comparable<T> { int compareTo(T other); }
相較於 Go 中不用明確宣告,在 Java 中實現 interface I
需要寫成 class T extends I
,因此雖然 Java 的 interface \(A\) 也有其相關的一組簽名 \(\hat P\),但兩個有同樣簽名 \(\hat P\) 的 interface 不是同一個型別。
而在 Java 中 bounded polymorphism 指的是以下的 interface 使用方法:
<S extends Comparable> S min(S a, S b)
這會使得沒有明確宣告實現 Comparable
的型別無法被傳為 min
的引數。
問題所在 [tt-000G]
- September 23, 2023
- Lîm Tsú-thuàn
問題所在 [tt-000G]
- September 23, 2023
- Lîm Tsú-thuàn
現在考慮一個簽名 \[ f : (S \le A) \Rightarrow S \times S \to S \] 在 Java 裡面可以確實保證兩個參數跟回傳的型別都是同一個。在 Go 裡面這個簽名就只能寫成 \[ f : \hat P \times \hat P \to \hat P \] 而兩個參數跟回傳的型別不一定相同。現在我們就會發現乍看之下 interface 對類型的約束跟多型一樣可以被多個不同的型別滿足,但事實上根本就是不同的東西。
interface 是一種子類型關係,換句話說當 \(T\) 實現 \(A\) 我們就說 \(T \le A\),在每個要求 \(A\) 的位置都可以用 \(T\) 取代。
多型的本體是一個型別等級的參數!在語意學上,上面的簽名可以改寫成 \(f : \Lambda S. S \times S \to S\),當你寫下 \[f \; k\] 的時候,乍看之下是一個完整的呼叫。實際上編譯器會先推導 \(k\) 的類型,記作 \(\uparrow k\),譬如假設 \(k : C\) 則 \(\uparrow k = C\),這時候就可以做型別替換 \((\Lambda S. S \times S \to S) C\) 得出 \(C \times C \to C\)。因此真正的呼叫程式碼是 \[f \; [C] \; k\]
子類型規則並不能取代替換這個語意。在 Java 的 \(f : (S \le A) \Rightarrow S \times S \to S\) 規則下,僅是多檢查了 \(C \le A\) 是否為真,子類型與多型仍然是不同的規則。
Pattern matching on Types: An indirected universe [tt-0005]
- September 15, 2023
- Lîm Tsú-thuàn
Pattern matching on Types: An indirected universe [tt-0005]
- September 15, 2023
- Lîm Tsú-thuàn
By introduce a indirect level of universe \(\mathcal {U}^-\), such that a subtype of normal universe \(\mathcal {U}\), and allows pattern matching. By restricting it can only be used at inductive type definitions' dependent position, it preserves parametricity, solves the problem easier compare with subscripting universe. In this setup, every defined type has type \(\mathcal {U}^-\) first, and hence
- \(\mathbb {N} : \mathcal {U}^-\)
- \(\mathbb {B} : \mathcal {U}^-\)
- \(\mathbb {L} : \mathcal {U} \to \mathcal {U}^-\)
\(\mathbb {L}\) didn't depend on \(\mathcal {U}^-\), so we keep using tagless encoding to explain
data Term Type | ℕ => add (Term ℕ) (Term ℕ) | 𝔹 => eq (Term ℕ) (Term ℕ) | a => if (Term 𝔹) (Term a) (Term a) | a => lit a
We have \(\text {Term} : \mathcal {U}^- \to \mathcal {U}^-\), and then, if one wants List (Term Nat)
it still work since \(\mathcal {U}^- \le \mathcal {U}\). But if one tries to define code below:
inductive Split Type^ | Nat => nat | Bool => bool | _ => else def id (A : Type) (x : A) : A => match Split A | nat => 0 | bool => false | _ => x
Since the \(\mathcal {U}\) isn't the subtype of \(\mathcal {U}^-\), program Split A
won't type check, the definition will not work as intended.
This is indeed more boring than subscripting universe, but easier to check it does't break parametricity.
Till now, I haven't start to check the pattern of type, except the primitive exact value, if I'm going to push this further, a good example is:inductive K Type^ | List a => hi a | _ => heThis is quite intuitive since in implementation inductive types' head are also rigid values, just like constructors.
Subscripting Universe [tt-0003]
- September 14, 2023
- Lîm Tsú-thuàn
Subscripting Universe [tt-0003]
- September 14, 2023
- Lîm Tsú-thuàn
This is an extension means to solve pattern matching on type's problem. We start from my old idea, an extension of inductive types.
Subscripting Inductive types [tt-0009]
- September 14, 2023
- Lîm Tsú-thuàn
Subscripting Inductive types [tt-0009]
- September 14, 2023
- Lîm Tsú-thuàn
An intutive extension of inductive types is, let constructor be subscripting set of the inductive type. For example, a type with definition
inductive Nat | zero | suc Nat
A type Nat[suc]
means only suc ...
is a term, zero
cannot have type Nat[suc]
. It's easy to see NatNonZero = Nat[suc]
, this can also apply to
List1 = List[cons]
-
Int
is also a good motive exampleinductive Int | 0 | + Int[+, zero] | - Int[-, zero]
Int[+]
is positive,Int[-]
is negative. The diagram in its syntactic category:
To ensure this, if the following syntax of each constructor c
is a list of argument types Ti ...
, we say the type of constructor of type T
is Ti ... -> T[c]
. The corresponding part is pattern matching's type rules will refine type T
with the pattern matched constructor c
, below marks all binder's refined type. The type T[c, ...]
is a subtype of T
.
def foo : Int -> Int | 0 => 0 | + p => -- p : Int[+, 0] p | - n => -- n : Int[-, 0] n
Remark. [#285]
- September 14, 2023
- Lîm Tsú-thuàn
Remark. [#285]
- September 14, 2023
- Lîm Tsú-thuàn
An obvious problem is
def neg : Int -> Int | 0 => 0 | + p => - (neg p) | - n => + (neg p)
We can see that the type information is squeezed, the second and third case need type casting. A potential solution is case type, and hence, neg
has type like:
But then what's the type rule of it? Will need some time to explore.
Extend to Universe [tt-000A]
- September 14, 2023
- Lîm Tsú-thuàn
Extend to Universe [tt-000A]
- September 14, 2023
- Lîm Tsú-thuàn
To extend this on to universe type Type
, we say if there is an inductive family T
inductive T (xi : Xi) ... | ci Ti ... | ...
, there is a binding T : Xi ... -> Type[T]
. As usual, Type[T, ...]
is a subtype of Type
. Therefore, in this configuration, writes down id : {A : Type} -> A -> A
still has the only one implementation! And we can do type pattern matching if we have subscriptings. Consider
- \(\mathcal {U}\) as
Type
- \(\mathbb {N}\) as
Nat
- \(\mathbb {B}\) as
Bool
- \(L\) as
List
we have an example diagram as below
A motive example is the tagless encoding:
data Term Type | ℕ => add (Term ℕ) (Term ℕ) | 𝔹 => eq (Term ℕ) (Term ℕ) | a => if (Term 𝔹) (Term a) (Term a) | a => lit a
The final we can consider subtyping more, should we generally introduce subset of subscriptings as super type? In this setup then Type[Nat, Bool] <: Type[Nat] <: Type
.
However, this is an over complicated idea, I prefer indirected universe more.
Generalize concept of element [math-0007]
- September 12, 2023
- Lîm Tsú-thuàn
Generalize concept of element [math-0007]
- September 12, 2023
- Lîm Tsú-thuàn
Element or member is a natural concept in set theory, one can use \(x \in A\) to denote \(x\) is an element of \(A\). We can extend the idea from view it in the category \(\bold {Sets}\):
Each element \(x\) of a set \(A\) corresponding to a function (set-morphism) \[ \{\bullet \} \xrightarrow {x} A \]
Therefore, if we admit a category \(\mathcal {C}\) has a terminal object \(1\), we say an element \(x\) of object \(A \in Ob(\mathcal {C})\) is a morphism \(1 \xrightarrow {x} A\).
NOTE: A terminal object \(1\) has exact one morphism from elsewhere, therefore each \(1 \xrightarrow {x} A\) is a proper representation of a single element \(x \in A\).
Theorem. Equal Arrow [math-0008]
- September 12, 2023
- Lîm Tsú-thuàn
Theorem. Equal Arrow [math-0008]
- September 12, 2023
- Lîm Tsú-thuàn
If \(A \xrightarrow {f} B\) and \(A \xrightarrow {g} B\) are morphisms in the category \(\mathcal {C}\) then \(f = g\) if and only if for every object \(X\) and every morphisms \(X \xrightarrow {x} A\) we have \(f x = g x\)
Proof. [#632]
- September 12, 2023
- Lîm Tsú-thuàn
Proof. [#632]
- September 12, 2023
- Lîm Tsú-thuàn
Pattern matching on type & following problems [tt-0001]
- September 10, 2023
- Lîm Tsú-thuàn
Pattern matching on type & following problems [tt-0001]
- September 10, 2023
- Lîm Tsú-thuàn
I'm considering a weird way to build inductive types, it's start on Zhang's idea, do pattern matching to get constructors.
Zhang's idea [tt-0006]
- December, 2021
- Lîm Tsú-thuàn
Zhang's idea [tt-0006]
- December, 2021
- Lîm Tsú-thuàn
The idea is coming from Zhang's paper, a simpler encoding of indexed types.
An example is Vec
in Agda
data Vec (A : Set a) : ℕ → Set a where [] : Vec A zero _∷_ : ∀ (x : A) (xs : Vec A n) → Vec A (suc n)
One can still try [] : Vec A 10
, although the type check failed, it need a sophisticated unification check.
With Zhang's idea, we can do:
data Vec (A : Set a) : ℕ → Set a where zero => [] suc n => _∷_ A (Vec A n)
Now, [] : Vec A n
where \(n \ne 0\) is impossible to write down as usual, but now it's an easier unification!
Since there has no constructor []
for type Vec A n
where \(n \ne 0\).
Another good example is finite set:
data Fin (n : N) | suc _ => fzero | suc n => fsuc (Fin n)
It requires overlapping pattern. One more last, we cannot define usual equality type here (please check)
data Id (A : Type ℓ) (x : A) : A → Type ℓ where idp : Id A x x
Paper: Simpler indexed type essentially simplifies the problem of constructor selection just by turning the term-match-term problem to a term-match-pattern problem, which rules out numerous complication but also loses the benefit of general indexed types.
The encoding problem of Zhang's idea [tt-0007]
- December, 2022
- Lîm Tsú-thuàn
The encoding problem of Zhang's idea [tt-0007]
- December, 2022
- Lîm Tsú-thuàn
The benefit of the idea is clear, but it disallows definition like tagless interpreter:
data Term : Set → Set1 where lit : ∀ {a} → a → Term a add : Term ℕ → Term ℕ → Term ℕ eq : Term ℕ → Term ℕ → Term 𝔹 if : ∀ {a} → Term 𝔹 → Term a → Term a → Term a eval : ∀ {a} → Term a → a eval (lit x) = x eval (add x y) = eval x + eval y eval (eq x y) = eval x == eval y eval (if c t e) with eval c eval (if c t e) | true = eval t eval (if c t e) | false = eval e
NOTE: There is a workaround in paper, and hence, the problem is inconvenience instead of impossible.
Pattern matching on Type as a solution [tt-0008]
- January, 2023
- Lîm Tsú-thuàn
Pattern matching on Type as a solution [tt-0008]
- January, 2023
- Lîm Tsú-thuàn
If I simply allow pattern matching on "Type", it's able to restore encoding from the problem:
data Term Type | ℕ => add (Term ℕ) (Term ℕ) | 𝔹 => eq (Term ℕ) (Term ℕ) | a => if (Term 𝔹) (Term a) (Term a) | a => lit a
But then it breaks parametricity! One now can read what is a polymorphic type concretely:
data C (A : Type) | ℕ => c1 | 𝔹 => c2 | _ => c3 id : {A : Type} -> C A -> A -> A id c1 x = 3 id c2 x = false id _ x = x
The first simple idea in my mind is forbiddingC P
whereThe question is, does this enough?
P
is a typeC
destruct aP
positionP
is a polymorphic type variable
Gödel incompleteness theorem 到底證明了什麼? [math-00BT]
- August 30, 2023
- Lîm Tsú-thuàn
Gödel incompleteness theorem 到底證明了什麼? [math-00BT]
- August 30, 2023
- Lîm Tsú-thuàn
哥德爾不完備定理是一個相當有趣的邏輯學發現,要了解他的意涵,要先考慮哥德爾的編碼
Gödel number [#431]
- August 30, 2023
- Lîm Tsú-thuàn
Gödel number [#431]
- August 30, 2023
- Lîm Tsú-thuàn
哥德爾數是一種編碼方式,在一個算術系統裡面,當我們把每個字符都排成一個有限的列,我們可以幫每個字符都指定一個自然數。具體來說,我們可能會寫下
Symbol | Number | Meta Meaning |
---|---|---|
\(\neg \) | 1 | not |
\(\lor \) | 2 | or |
\(\land \) | 3 | and |
\(\cdots \) | n | \(\cdots \) |
當有符號 \(s_i (i \in \N )\),其對應的哥德爾數為 \(n_i\)。我們並不是真的關心具體的每個符號,我們做這件事的理由是為了表示哥德爾編碼。所以這裡要開始定義哥德爾編碼,首先先看一個簡單的例子:當有系統的公式符號排列 \(s_1 s_{10} s_4\),我們說公式的哥德爾編碼為 \(2^{n_1}\cdot 3^{n_{10}}\cdot 5^{n_4}\)。
因此用函數 \(\alpha (i)\) 指示一個公式的每個位置 \(i\) 符號的 Gödel number,則哥德爾編碼確切的定義是
\[\prod _{i \in I}p_i^{n_{\alpha (i)}}\],也就是將質數以每個符號對應的哥德爾數為指數,將它們全部乘起來。這個辦法只是為了迫使每個公式有對應的編碼存在。我們用 \(\overline {G}\) 記號表示公式 \(G\) 的哥德爾數。
\(\alpha \) 函數給出第 \(i\) 個出現符號的在表中的位置。
在承認前述的系統 \(P\) 下,可以開始描述。
Theorem. Gödel incompleteness [math-00BU]
- August 30, 2023
- Lîm Tsú-thuàn
Theorem. Gödel incompleteness [math-00BU]
- August 30, 2023
- Lîm Tsú-thuàn
- 存在形式上不能證明卻是真確、可寫下的公式
- 用系統證明自身的一致性會導致不可決定的公式也被證明
Definition. Substitution [#428]
- August 30, 2023
- Lîm Tsú-thuàn
Definition. Substitution [#428]
- August 30, 2023
- Lîm Tsú-thuàn
\(x[m/n]\) 表示將公式 \(x\) 中哥德爾數為 \(n\) 之符號換成 \(m\) 的哥德爾數再求此替換後公式的哥德爾編碼。
例如 \(\neg y[n/\overline {y}] = \overline {\neg n}\)
Proof. [#430]
- August 30, 2023
- Lîm Tsú-thuàn
Proof. [#430]
- August 30, 2023
- Lîm Tsú-thuàn
首先,用 \(\exists x. x \vdash k\) 表示有哥德爾數為 \(k\) 的公式在系統 \(P\) 中得到證明,而 \(x\) 是其演示
Remark. [#429]
- August 30, 2023
- Lîm Tsú-thuàn
Remark. [#429]
- August 30, 2023
- Lîm Tsú-thuàn
哥德爾有一段很長的論證,證明這是原始遞歸函數,以說明這是可以被 \(P\) 表示的,這裡跳過了這部分論證。且這也是為什麼要求系統 \(P\) 是具備算術能力的,因為表示編碼需要自然數算術。
定義 \(n = \lnot \exists x. x \vdash y[y/y]\),但 \(y\) 是未知量,隨意給一個還沒被使用來編碼的數字即可,比如 \(\overline {y}\)。於是我們重寫成 \(n = \lnot \exists x. x \vdash y[y/\overline {y}]\)。
現在構造 \(G = \lnot \exists x. x \vdash n[n/\overline {y}]\),求其哥德爾編碼 \(\overline {G}\) 可以發現正是 \(n[n/\overline {y}]\) 所表示的編碼,因為
\[ n[n/\overline {y}] = \overline {\lnot \exists x. x \vdash n[n/\overline {y}]} = \overline {G} \]因此用 \(\overline {G}\) 替換 \(G\) 中的 \(n[n/\overline {y}]\),會得到
\[\lnot \exists x. x \vdash \overline {G}\]可以發現 \(G\) 的後設含義正是「有哥德爾編碼為 \(\overline {G}\) 的公式沒有系統 \(P\) 中的證明」,然而
- 假設 \(G\) 可以在 \(P\) 中證明為真,就告訴我們 \(\overline {G}\) 對應的公式不存在任何演示可以於 \(P\) 中證明,但那就是我們剛證明的公式 \(G\)。
- 假設 \(G\) 可以在 \(P\) 中證明為否,就導出 \(\overline {G}\) 對應的公式在 \(P\) 中有演示,但那就是我們剛證否的公式 \(G\)。
綜合可知這意思就是 \(G\) 可證,若且唯若 \(G\) 可證否,是故承認 \(G\) 就是承認 \(P\) 不一致;反之,若 \(P\) 一致則 \(G\) 形式上就不可決定。
巧妙的是,並不難看出 \(G\) 的 meta 陳述是真確的,因為確實不存在任何整數作為編碼滿足這個性質。換句話說,存在形式上不能證明卻是真確、可寫下的公式,這就是第一不完備定理。接著根據第一不完備定理知道了 \(G\) 的真確性,卻在 \(P\) 中形式上不可決定,所以 \(P\) 不能證明一個真確的算術公式,因此 \(P\) 必定是不完備的,這就是第二不完備定理。
Conclusion. [#432]
- August 30, 2023
- Lîm Tsú-thuàn
Conclusion. [#432]
- August 30, 2023
- Lîm Tsú-thuàn
因此在 The Blind Spot: Lectures on Logic 中可以看到對兩個定理的陳述更加關注核心:對一個足夠編碼自己又一致的系統
- 存在一個真確的公式 \(G\) 不可決定
- 系統證明自己具有一致性會連帶證明這個不可決定的公式,所以系統無法證明自己的一致性
換句話說,要關心的並不是具體如何構造上面陳述的編碼,而是這類系統編碼系統自身的普遍性問題。
型別有多大? [tt-0013]
- July 1, 2023
- Lîm Tsú-thuàn
型別有多大? [tt-0013]
- July 1, 2023
- Lîm Tsú-thuàn
不久之前看到 fizzyelt 的文章,所我前幾日開始研究自己以前寫的 strictly positive 筆記,因此找到了 Andrej Bauer 在 stackexchange 的回答,整理後寫了這篇文章解釋何謂型別的大小
型別的大小 [tt-0014]
- July 1, 2023
- Lîm Tsú-thuàn
型別的大小 [tt-0014]
- July 1, 2023
- Lîm Tsú-thuàn
要了解型別的大小的意義,可以先考慮一個 small cartesian closed category,令型別是此範疇的物件(只有一個型別的 context)。
應用 slice category [tt-0016]
- July 1, 2023
- Lîm Tsú-thuàn
應用 slice category [tt-0016]
- July 1, 2023
- Lîm Tsú-thuàn
在這個情況下,對任意型別 \(t\),slice category \(C/t\) 表示「到達 \(t\) 的 morphism」所構成的集合,也就是 \(C/t\) 的 objects。
Example. 從 \(1\) 出發 [tt-0017]
- July 1, 2023
- Lîm Tsú-thuàn
Example. 從 \(1\) 出發 [tt-0017]
- July 1, 2023
- Lîm Tsú-thuàn
接著,我們要關心其中沒定義的 morphism,我們將基於此集合討論型別 \(T\) 有多大。技術上來說,是指從 terminal object \(1\) 出發的所有 morphisms(記為 \(\text {Hom}_{C}(1, T)\)),這些 morphisms 對應到內建的形式;以邏輯來說是指公理,而在函數式語言裡面,我們最常看到的定義公理的方式就是 data type!換句話說,型別的大小由建構子決定:
- \(0\) 是 False / Empty type,沒有任何建構子
- \(1\) 是 Unit type,只有一個建構子
- \(2\) 是 Bool type,只有兩個建構子
依此類推可以知道有 \(k\) 個單元建構子(即建構子 c
滿足 c : K
)的型別 K
可以解釋為 \(k\)-type,接著 \(2 \to T\) 的元素應該有幾個呢?答案是 \(T \times T = T^2\),同理我們可以建立 \(k \to T = T \times ... \times T = T^k\) 的關係式。
依此可以建立一個簡單的直覺是 c : T
表示 \(+1\),而更加複雜的型別如 c : (2 -> T) -> T
就表示 \(+T^2\),建構子的參數表現了型別增長的速度,決定了型別的大小。
一個常見的案例是自然數,我們通常定義 \(z : \N \) 和 \(s : \N \to \N \) 兩個建構子來表示自然數 \(\N \)。用 F-algebra 來表示,可以得到 \((1 + \mathbb {N}) \to \mathbb {N}\),從沒有循環參考的角度來看,當前 \(\N \) 的大小即取決於上一個 \(\N \) 的大小。畫出交換圖就可以了解到從基本點 \(z\) 出發,只有 \(s\) 一個方向可以前進,恰恰就是可數無限大的定義,是以看到這與歸納法的對應時,應當不會太過驚訝。
Inductive data type [tt-0018]
- July 1, 2023
- Lîm Tsú-thuàn
Inductive data type [tt-0018]
- July 1, 2023
- Lîm Tsú-thuàn
在 dependent type 語言裡面,data type 會變成 inductive data type,引入了更多的限制,而其中跟大小有關的限制就是這裡想要討論的。
Question. 在定義建構子時 c : (T -> T) -> T
有參數 \(T^T\) ,試問 \(T^T\) 有多大? [#255]
- July 1, 2023
- Lîm Tsú-thuàn
Question. 在定義建構子時 c : (T -> T) -> T
有參數 \(T^T\) ,試問 \(T^T\) 有多大? [#255]
- July 1, 2023
- Lîm Tsú-thuàn
答案是不知道,因為我們根本還不知道 \(T\) 到底是什麼。
Remark. [#256]
- July 1, 2023
- Lîm Tsú-thuàn
Remark. [#256]
- July 1, 2023
- Lîm Tsú-thuàn
當 \(T\) 定義完畢之後,這個簽名用在函數上倒是沒有問題,因為其大小已經確定,不會遇到自我指涉引發的麻煩。
雖然可以用公理強迫 \(T^T\) 有 size,但這樣做一來會破壞計算性;二來會顯著的複雜化 termination check。舉例來說,要是容許定義 c
,就可以寫出
def foo (t : T) : T := match t with | c f => f t
接著 foo (c foo)
就會陷入無限迴圈,為了要有強正規化,我們希望排除所有這類型的程式,比起一個一個去比對,直接禁止定義 c
這類的建構子可以更簡單的達成目的。Haskell/OCaml 的 data type 則不做此限制,因為它們不需要強正規化,這也是為什麼 dependent type 語言常説其 data type 是 inductive data type,並不輕易省略 inductive 這個詞,因為這樣定義的類型滿足 induction principle。
另外一提,Bauer 的回答談到所有建構子都是為了符合 \(c : \Pi _{x : B} (A \; x \to T) \to T\) 的形式,有興趣的讀者可以著手證明。此外 strictly positive 的遞迴定義可能更適合實現檢查機制。
遞迴 [tt-0015]
- July 1, 2023
- Lîm Tsú-thuàn
遞迴 [tt-0015]
- July 1, 2023
- Lîm Tsú-thuàn
把程式作為 object,而 continuation 作為 morphism,就可以發現尾遞迴完全對應到迴圈這個抽象,兩者都有
- \(b : c \to k\) base case 與 break
- \(n : c \to c\) induction case 與 next step
這兩個 morphism。從構造的角度來看,還可以說他們跟自然數有對應,上面的簽名恰恰正是 initial 跟 step。
分形遞迴(Tree Recursion) [tt-0019]
- July 1, 2023
- Lîm Tsú-thuàn
分形遞迴(Tree Recursion) [tt-0019]
- July 1, 2023
- Lîm Tsú-thuàn
典型的情況是 fibonacci 數列,展示了前面的型別大小如何與程式相關,常見的程式定義如下
def fib : Nat → Nat | 0 => 1 | 1 => 1 | n+2 => fib n + fib (n+1)
為了抽出計算部分的代數,我們用 inductive type 定義其計算
inductive Fib (a : Type) : Nat → Type where | z : a → Fib a 0 | o : a → Fib a 1 | s : Fib a n → Fib a (n+1) → Fib a (n + 2)
可以看到 induction case 就是 \((2 \to F a) \to F a = {F a}^2 \to F a = F a \times F a \to F a\),所以對應的程式就是兩次呼叫 fib n + fib (n+1)
。當然,因為 fibonacci 還有一個利用矩陣計算的編碼
這個方法對應到 \(O(n)\) 的演算法,因此 fibonacci 不一定要用分形遞迴計算。這件事也告訴了我們代數簽名有時候比我們具體的計算更寬鬆,上面的 inductive type 並未限制如何使用 s
,也因此可以摺疊時可能存在更快的計算方式。這也說明了當遇到 c : (T -> T) -> T
一類的建構子時,其對應的計算難以寫出的問題,也就是前面沒辦法定義 \(T^T\) 的大小的情形。
Parser combinator:文法規則就是組合子的運用 [cs-000S]
- June 4, 2023
- Lîm Tsú-thuàn
Parser combinator:文法規則就是組合子的運用 [cs-000S]
- June 4, 2023
- Lîm Tsú-thuàn
這裡的想法我以前就在部落格裡面提到了,但是當時的設計並不夠通用,隨著後來拿來寫其他專案的時候標出型別就有了更廣泛的想法。
Definition. 左遞迴 [cs-000L]
- June 4, 2023
- Lîm Tsú-thuàn
Definition. 左遞迴 [cs-000L]
- June 4, 2023
- Lîm Tsú-thuàn
左遞迴是我們定義文法的時候會出現的一種形式,比如
\[\begin {equation} Expr \to Expr + Expr \end {equation}\]翻譯成遞歸下降解析器時會有像下面這樣的程式
def expr : Parsec E := let l <- expr match '+' let r <- expr return E.add l r
這時候 expr
顯然是一個非終止的發散函數,而因為遞迴的原因是運算式的左邊,所以被稱為左遞迴。這樣的 infix 運算形式在文法中很常見,所以我們需要方法來消除文法中的左遞迴。
Definition. Parser combinator [cs-000M]
- June 4, 2023
- Lîm Tsú-thuàn
Definition. Parser combinator [cs-000M]
- June 4, 2023
- Lîm Tsú-thuàn
解析器組合子(parser combinator)最早來自論文 A new top-down parsing algorithm to accommodate ambiguity and left recursion in polynomial time, 在現在的使用中因為不同語言特性跟 parser combinator 指涉的比較像是一種程式方法的情況下,本文中的 parser combinator 是單純指把 parser 跟 higher order function 結合的一種程式方法。這個方案最大的好處就是遞歸下降解析跟程式寫法一一對應,因此相當直覺。
在遞歸下降解析中消除左遞迴的方法 [cs-000N]
- June 4, 2023
- Lîm Tsú-thuàn
在遞歸下降解析中消除左遞迴的方法 [cs-000N]
- June 4, 2023
- Lîm Tsú-thuàn
現在你知道為什麼我們需要了解遞歸下降解析中消除左遞迴的方式,以下面文法來說
\[\begin {align} Expr \to \; &Expr + Expr \\ | \; &Int \\ | \; &( Expr ) \end {align}\]我們可能會將定義改成
\[\begin {align} Expr &\to Term + Term \\ Term &\to Int \; | \; ( Expr ) \end {align}\]這個解法在對應的 parser combinator 中看起來像是
mutual def term := parse_int <|> parens expr def expr : Parsec E := let l <- term match '+' let r <- term return E.add l r end
擴展到 operator 優先序問題 [cs-000O]
- June 4, 2023
- Lîm Tsú-thuàn
擴展到 operator 優先序問題 [cs-000O]
- June 4, 2023
- Lîm Tsú-thuàn
上面的方法解決了左遞迴問題,但是要是有多個不同優先級的運算形式就會讓文法快速膨脹
\[\begin {align} Expr &\to Term + Term \\ Term &\to Factor * Factor \\ Factor &\to Int \; | \; ( Expr ) \end {align}\]這樣單調的修改在文法裡面確實很無聊,不過只要仔細觀察對應的 combinator,就會它們的型別發現這告訴了我們要怎麼利用 higher order function 來解決重複的問題!對 infix 運算形式(左結合)來說,通用的程式是
def infixL (op : Parsec (α → α → α)) (tm : Parsec α) : Parsec α := do let l ← tm match ← tryP op with | .some f => return f l (← tm) | .none => return l
這個 combinator 先解析左邊的 lowertm
,接著要是能夠解析op
就回傳op
combinator 中存放的函數,否則就回傳左半邊的tm
結果。使用上就像這樣
mutual def factor : Parsec Expr def expr : Parsec Expr := factor |> infixL (parseString "*" *> return Expr.mul) |> infixL (parseString "+" *> return Expr.add) end
- 其中
parseString
是個假設會進行 whitespace 過濾並 match 目標字串的 combinator -
Expr.mul
跟Expr.add
的型別被假設為Expr → Expr → Expr
這裡真正發生的就是使用組合子編碼了文法的層級,其中每個規則都被記錄成匿名函數,我們無需再另外命名。
處理優先度相同的運算子 [cs-000P]
- June 4, 2023
- Lîm Tsú-thuàn
處理優先度相同的運算子 [cs-000P]
- June 4, 2023
- Lîm Tsú-thuàn
因為有些運算子優先級相同,所以我們還需要再修改上面的函數來正確的支援這個概念;而且上面的程式為了避免複雜化,只解析一次 operator 加上 tm
就退出了,會導致實際上 1 + 2 * 3 * 4
這種算式的 * 4
部分沒有被解析。要解決這個問題,我們需要貪婪解析右半邊 op tm
的部分。綜上所述我們得到的程式碼是
def infixL (opList : List (Parsec (α → α → α))) (tm : Parsec α) : Parsec α := do let l ← tm let rs ← many do for findOp in opList do match ← tryP findOp with | .some f => return (f, ← tm) | .none => continue fail "cannot match any operator" return rs.foldl (fun lhs (bin, rhs) => (bin lhs rhs)) l
首先我們有一串 operator 而非一個,其次在右邊能被解析成 op tm
時都進行解析,最後用 foldl
把結果轉換成壓縮後的 α
Conclusion. 對文法規則的運用 [cs-000Q]
- June 4, 2023
- Lîm Tsú-thuàn
Conclusion. 對文法規則的運用 [cs-000Q]
- June 4, 2023
- Lîm Tsú-thuàn
我希望這次有成功解釋怎麼從規則對應到 parser combinator,所以相似的規則可以抽出相似的 higher order function 來泛化,讓繁瑣的規則命名變成簡單的函數組合。這個技巧當然不會只有在這裡被使用,只要遇到相似形的文法都可以進行類似的抽換,相似的型別簽名可以導出通用化的關鍵。
Appendix. 其他 expression combinator [cs-000R]
- June 4, 2023
- Lîm Tsú-thuàn
Appendix. 其他 expression combinator [cs-000R]
- June 4, 2023
- Lîm Tsú-thuàn
在這裏提到的所有程式都實作在我幫 lean 寫的一個解析器擴充程式庫 parsec-extra 中
-
右結合的 infix
partial def infixR (opList : List (Parsec (α → α → α))) (tm : Parsec α) : Parsec α := go #[] where go (ls : Array (α × (α → α → α))) : Parsec α := do let lhs ← tm for findOp in opList do match ← tryP findOp with | .some f => return ← go (ls.push (lhs, f)) | .none => continue let rhs := lhs return ls.foldr (fun (lhs, bin) rhs => bin lhs rhs) rhs
-
prefix
op tm
def «prefix» (opList : List $ Parsec (α → α)) (tm : Parsec α) : Parsec α := do let mut op := .none for findOp in opList do op ← tryP findOp if op.isSome then break match op with | .none => tm | .some f => return f (← tm)
-
postfix
op tm
def «postfix» (opList : List $ Parsec (α → α)) (tm : Parsec α) : Parsec α := do let e ← tm let mut op := .none for findOp in opList do op ← tryP findOp if op.isSome then break match op with | .none => return e | .some f => return f e
Cones, their category, and limit [math-002L]
- March 20, 2023
- Lîm Tsú-thuàn
Cones, their category, and limit [math-002L]
- March 20, 2023
- Lîm Tsú-thuàn
In category theory, cone is a kind of natural transformation, to describe a diagram formally. The setup of cone is starting from a diagram, which we will define it as a category \(\mathcal {D}\) (usually is a finite one but no need to be) with two functors to the target category \(\mathcal {C}\). The two functors are
- \(\Delta _c\) takes all objects of \(\mathcal {D}\) to a certain \(\mathcal {C}\)-object \(c\), and all morphisms to the identity \(1_c\)
- \(F\) sends the diagram \(\mathcal {D}\) entirely into \(\mathcal {C}\)
The first functor is very clear, we always can do that for any category; the second functor will need \(\mathcal {C}\) has that diagram. Consider \(\mathcal {D}\) as below
If such diagram exists in \(\mathcal {C}\), then we have a proper way to define \(F\), there can have many such diagram in \(\mathcal {C}\), we denote them as \(\mathcal {C}(\mathcal {D})\). Now consider if there is a morphism from \(c\) to all objects in \(\mathcal {C}(\mathcal {D})\), that lift a natural transformation from \(\Delta _c \to F\).
We say \(c\) is an apex and the \(\mathcal {C}(\mathcal {D})\) is a plane in this sense, thus, such a natural transformation gives concept cone. With a fixed functor \(F\) (we also abuse language to say \(F\) is the diagram), varies \(\Delta _c\) bring different cones! When I get this, the picture in my mind is:
Image the head is apex and the body is the fixed diagram \(F\), you will also get the idea slowly.
To describe above idea, we make another category! By picking all apex of cone as objects, and picking morphism between apex in \(\mathcal {C}\) as morphisms, this is the category of cones (please check it does really a category).
Definition. Category of (co)cones [math-002M]
- March 20, 2023
- Lîm Tsú-thuàn
Definition. Category of (co)cones [math-002M]
- March 20, 2023
- Lîm Tsú-thuàn
With a fixed diagram \(\mathcal {D} \xrightarrow {F} \mathcal {C}\) and existing natural transformations \(\Delta _c \to F\), we get a category that consituited by
\(\Delta _c\) is a functor \(- \mapsto c : \mathcal {D} \to \mathcal {C}\) various on different \(c \in \mathcal {C}\).
- objects: all cone objects \(c\) above the fixed diagram (via \(\Delta _c\) functor).
- morphisms: \(\mathcal {C}\)-morphisms between cones.
Dual natural transformations \(F \xrightarrow {\beta } \Delta _c\) form cocones and a dual category.
The funny part we care here, is the terminal object of the category of cones, that is the next section. A limit or universal cone is a terminal object of category of cones. If you consider it carefully, and you will find this is the best cone of cones, because every other cones can be represented by composition of an addition morphism from itself to the limit!
Definition. Limit and colimit (universal cone and cocone) [math-002N]
- March 20, 2023
- Lîm Tsú-thuàn
Definition. Limit and colimit (universal cone and cocone) [math-002N]
- March 20, 2023
- Lîm Tsú-thuàn
With a fixed diagram \(\mathcal {D} \xrightarrow {F} \mathcal {C}\), a limit is a terminal of the category of cones, denoted as \(\lim _{\mathcal {D}} F\).
- notice that we can freely abuse language and say a \(\mathcal {C}\)-diagram is a functor target to \(\mathcal {C}\)
- Limit might not exist, so you have to ensure there has one.
The dual concept colimit is an initial of category of cocones, denoted as \(\underset {\mathcal {D}} {\text {colim}}F\).
With concept of cone and limit, you might already find there has some concept can be replaced by cone and limit, you're right and that would be fun to rewrite them in this new sense. Have a nice day.
什麼是啟動編譯器? (bootstrap compiler) [cs-000V]
- December 31, 2022
- Lîm Tsú-thuàn
什麼是啟動編譯器? (bootstrap compiler) [cs-000V]
- December 31, 2022
- Lîm Tsú-thuàn
當一個語言逐漸成熟,開發者常常會有一個想法就是用自己開發的語言寫這個語言的編譯器,但是這個決策會導致程式庫中有兩套目標一樣但是實現語言不同的編譯器程式。其一是本來的實現,另一個是用語言自身新寫的。一來這樣開發任何新功能的時候都需要寫兩次;二來這會減少可能的參與者人數,因為這下他得要熟悉兩個語言才行!解決這個問題的辦法就是啟動編譯器,通常是一個在多平台上可以直接執行的檔案。
Definition. 原理 [cs-000W]
- December 31, 2022
- Lîm Tsú-thuàn
Definition. 原理 [cs-000W]
- December 31, 2022
- Lîm Tsú-thuàn
約略是下面描述的樣子:
- 語言本身後端的目標語言可以生成這個啟動編譯器,讓我們先用可執行檔簡單理解它,後面再闡述為什麼用普通的可執行檔可能不是一個好主意
- 每次編譯器用到新的特性的時候,都需要更新啟動編譯器檔案並提交進程式庫
- 有了上述準備,就可以在第一次編譯編譯器自身的時候,用啟動編譯器編譯出最佳化過的編譯器執行檔
現在有了最佳化過的編譯器執行檔,就可以正常的使用語言自己對語言自己進行開發了。
現在可以來想一下為什麼是這樣的流程,首先一個程式語言除非被大量作業系統支援(比如 C、Python),否則系統上是不會有這個程式語言的編譯器的!這樣問題就來了:假設有人試圖參與這個編譯器專案,用的平台剛好跟既有開發者都不一樣,請問要由誰提供已經用語言自身編寫的編譯器的編譯器呢?想當然除了一些喪心病狂的作法,是不可能完成這個任務的!所以一個無論如何都已經可以執行的編譯器,哪怕效能比較差,也具有存在的價值。
而語言自身的編譯器用到新功能的時候,也一定要更新啟動編譯器,否則下一輪的新參與者就沒辦法正確的進行初始編譯。
用普通的可執行檔可能不是一個好主意 [cs-000X]
- December 31, 2022
- Lîm Tsú-thuàn
用普通的可執行檔可能不是一個好主意 [cs-000X]
- December 31, 2022
- Lîm Tsú-thuàn
前面提過說啟動編譯器通常是一個在多平台上可以直接執行的檔案,也提過哪怕效能不佳也可以,這兩個理由使得特定平台的可執行檔不是一個好的選擇。 當然,我們也可以選擇維護每個平台的啟動編譯器,chez scheme 就維護了一堆根據不同平台套用組合的二進位檔案做這件事。
回到正題上,啟動編譯器通常不會選擇這麼複雜的方式,而是會生成可以在多平台上執行的檔案。舉例來說,生成 C 或是 Python 這種已經被許多系統廣泛支援的語言,最近 zig 就是使用 wasm 達成這個目標。但這個選擇也不能太過隨便,比如要是語言自己的 type checking 任務很長,生成 Python 就會得到一個大家都不想等它跑完就不玩了的啟動編譯器。而限制太多的語言像是 haskell 或是 rust 可能也不是優秀的選擇,因為你的語言模型很可能跟這些目標語言非常不相配,進而讓編譯過程非常的痛苦。
Conclusion. [cs-000Y]
- December 31, 2022
- Lîm Tsú-thuàn
Conclusion. [cs-000Y]
- December 31, 2022
- Lîm Tsú-thuàn
有了這些概念,我想你已經有能力為自己的語言寫出啟動編譯器了!那麼剩下的篇幅我就可以來寫點 murmur,我覺得這個概念可以進一步推升到選擇一個夠容易編譯出來,也夠容易寫出通用最佳化編譯器的語言來達成。我個人是很看好 wasm,因為它確實容易當目標、最佳化,只可惜現在還有不少重要的功能都沒有定案。llvm 的 bytecode 確實也是一個方案,寫一個把 llvm bytecode 編譯成 executable 的 python 檔案並不困難,但 llvm 的連結性自己就是一個天殺的大麻煩所以這個方案我很少看到有人使用。Java bytecode 則是讓那些本來就預計只在 JRE 生態系內部的語言從一開始就沒有這個問題,微軟的 CLR 也是類似的狀況,缺陷是最後語言受制於 runtime,這個問題會有多大條取決於語言的目的是什麼。
好像是今年最後一天了,祝你不是在今天看到這篇文章的!
解析 conversion check [tt-001C]
- November 25, 2022
- Lîm Tsú-thuàn
解析 conversion check [tt-001C]
- November 25, 2022
- Lîm Tsú-thuàn
今天要解析的是 Elaboration zoo 中的一段程式,其中用到了 conversion check 的技術。這種合一演算法在 dependent type 語言裡面是主要的核心問題
型別檢查 [tt-001D]
- November 25, 2022
- Lîm Tsú-thuàn
型別檢查 [tt-001D]
- November 25, 2022
- Lîm Tsú-thuàn
這裡列出重要的兩個定義:
- environment:儲存變數的計算結果
- context:儲存變數的型別
type Env = [(Name, Val)] type Ctx = [(Name, VTy)]
下面逐步介紹整個型別檢查的元件
推導 inference [tt-001F]
- November 25, 2022
- Lîm Tsú-thuàn
推導 inference [tt-001F]
- November 25, 2022
- Lîm Tsú-thuàn
在最上層的程式中,推導函數會直接被調用來得出 term 的 type,它會適當的調用 check
去檢查是否有型別錯誤
infer :: Env -> Ctx -> Raw -> M VTy infer env ctx = \case SrcPos pos t -> addPos pos (infer env ctx t) Var x -> case lookup x ctx of Just a -> return a Nothing -> report $ "Name not found: " ++ x U -> return VU t :@ u -> do tty <- infer env ctx t case tty of VPi _ a b -> do check env ctx u a return $ b $ eval env u tty -> report $ "Cannot apply on: " ++ quoteShow env tty Lam {} -> report "cannot infer type for lambda expression" Pi x a b -> do check env ctx a VU check ((x, VVar x) : env) ((x, eval env a) : ctx) b VU return VU Let x a t u -> do check env ctx a VU let ~a' = eval env a check env ctx t a' infer ((x, eval env t) : env) ((x, a') : ctx) u
-
SrcPos
這個情況只需要加上位置訊息之後往下 forward 即可 - 遇到變數時,查找當前的 context 就可以知道型別了
- 再來 universe 的 type 就是 universe
- application (
t :@ u
) 也就是函數套用 (\(\beta \)-reduction) 的情況就比較複雜了- 首先要馬上推導
t
得到tty
- 要是
tty
不是一個函數型別 (\(\Pi \) type) 那麼就回報錯誤 - 否則
tty
的形式就會是 \(\Pi (x:A) \to B\),這時候要檢查u
是否是一個 \(A\) - 最後一步把 \(\Pi (x:A)\to B\) 套用
u
就會得到型別 \(B\ x\),也就是目標
- 首先要馬上推導
- lambda 設定成不能推導,避開 undecidable 的情況
- 對 \(\Pi (x : A) \to B\) 先檢查 \(A\) 是不是型別 (\(\mathbb {U}\)) ,接著擴張 environment 跟 context 再檢查 \(B\ x\) 是不是 \(\mathbb {U}\)
- let 語法寫成
let x : a = t in u
,推導的過程如下- 檢查
a
是型別 - 執行
a
得到a'
,因為要從Tm
變成Val
(也就是化簡過的a
) - 檢查
t
的型別是否是a'
- 把
x : a'
與x = t
的綁定資訊推進 context 與 environment 再拿它們去推導u
- 檢查
最後使用 infer
時,就像是這樣 (...
是省略號):
tm <- parse ... case infer [] [] tm of Left err -> ... Right ty -> ...
檢查 check [tt-001G]
- November 25, 2022
- Lîm Tsú-thuàn
檢查 check [tt-001G]
- November 25, 2022
- Lîm Tsú-thuàn
檢查函數接收一個 term 跟一個 type 用來找出 term 實際類型不匹配 type 的情況
check :: Env -> Ctx -> Raw -> VTy -> M () check env ctx t a = case (t, a) of (SrcPos pos t, _) -> addPos pos (check env ctx t a) (Lam x t, VPi (fresh env -> x') a b) -> -- after replace x in b -- check t : bx check ((x, VVar x') : env) ((x, a) : ctx) t (b (VVar x')) (Let x a' t' u, _) -> do check env ctx a' VU let ~a'' = eval env a' check env ctx t' a'' check ((x, eval env t') : env) ((x, a'') : ctx) u a _ -> do tty <- infer env ctx t unless (conv env tty a) $ report (printf "type mismatch\n\nexpected type:\n\n \%s\n\ninferred type:\n\n \%s\n" (quoteShow env a) (quoteShow env tty))
-
SrcPos
這個情況只需要加上位置訊息之後往下 forward 即可 - 要是 term 是 lambda \(\lambda x . t\) 且 type 是 \(\Pi (x' : A) \to B\)
- 這裡 \(\Pi \) type 用了 view patterns 這個 extension:
fresh env -> x'
- 這部份是因為
x
跟x'
可能是同名的,fresh
確保了它們不會被搞混 - 這個語法的意思是
expression -> pattern
- pattern 用來 matching
- expression 在 match 到之後套用到該 pattern 對應的 expression
- 這部份是因為
- 接著讓環境擴張成
x = x'
跟x : A
- 拿新環境檢查
t
(lambda 的 body)的型別是不是 \(B\ x\)檢查 lambda 的方式就是讓 lambda 跟 \(\Pi \) 套用同一個參數之後再看一次
- 這裡 \(\Pi \) type 用了 view patterns 這個 extension:
- term 是 let 語法時跟推導的情況完全一樣,只差在最後一段是檢查
u
在新環境下是不是check
拿到的那個 type 而不是去推導u
- 除此之外的情況就是調用回去
infer
找出 term 的型別,然後讓它跟check
拿到的 type 做 conversion check
化簡 evaluation [tt-001H]
- November 25, 2022
- Lîm Tsú-thuàn
化簡 evaluation [tt-001H]
- November 25, 2022
- Lîm Tsú-thuàn
化簡函數就是把 term 變成 value 的過程,它只需要 environment 而不需要 context
eval :: Env -> Tm -> Val eval env = \case SrcPos _ t -> eval env t Var x -> fromJust $ lookup x env t' :@ u' -> case (eval env t', eval env u') of (VLam _ t, u) -> t u (t, u) -> VApp t u U -> VU Lam x t -> VLam x (\u -> eval ((x, u) : env) t) Pi x a b -> VPi x (eval env a) (\u -> eval ((x, u) : env) b) Let x _ t u -> eval ((x, eval env t) : env) u
-
SrcPos
一如既往的只是 forward - 變數就是上環境尋找
- \(\beta \)-reduction 的情形就是先化簡要操作的兩端,然後看情況
- 函數那頭是 lambda,就可以當場套用它的 host lambda 得到結果
- 這個情形比較有趣,有很多名字像是卡住、中性之類的描述,簡單來說就是沒辦法繼續化簡的情況。我們用
VApp
儲存這個結果,conversion check 裡面會講到怎麼處理這些東西VApp
也常被叫做 spine
- universe 的值還是 universe
- lambda 跟 \(\Pi \) 好玩的地方在使用 host lambda 編碼計算,這個 lambda 定義成
\u -> ...
- 會用
u
去擴展 environment,也就是(x, u) : env
- 接著用擴展的 environment 執行
t
(在 \(\Pi \) 的情況就是執行b
)
- 會用
- let x : a = t in u 語法就是把 x = t 丟進 environment 去執行 u 而已
Remark. [#282]
- November 25, 2022
- Lîm Tsú-thuàn
Remark. [#282]
- November 25, 2022
- Lîm Tsú-thuàn
卡住在 dependent type 裡非常常見,舉例來說你有個函數
foo : (f : A -> U) -> (a : A) -> f a
在檢查 foo
時執行到 f a
就沒辦法被化簡,因為此時我們拿到的 f
是一個 VVar "f"
而不是 VLam x t
Conversion check 可轉換性檢查 [tt-001I]
- November 25, 2022
- Lîm Tsú-thuàn
Conversion check 可轉換性檢查 [tt-001I]
- November 25, 2022
- Lîm Tsú-thuàn
conversion 是在 environment 中判斷兩個 value 是否能夠互相轉換的函數,對型別來說就是在判斷兩個型別是否相同
conv :: Env -> Val -> Val -> Bool conv env m n = case (m, n) of (VU, VU) -> True (VPi (fresh env -> x) a b, VPi x' a' b') -> conv env a a' && conv ((x, VVar x) : env) (b (VVar x)) (b' (VVar x)) (VLam (fresh env -> x) t, VLam x' t') -> conv ((x, VVar x) : env) (t (VVar x)) (t' (VVar x)) (VLam (fresh env -> x) t, u) -> conv ((x, VVar x) : env) (t (VVar x)) (VApp u (VVar x)) (u, VLam (fresh env -> x) t) -> conv ((x, VVar x) : env) (VApp u (VVar x)) (t (VVar x)) (VVar x, VVar x') -> x == x' (VApp t u, VApp t' u') -> conv env t t' && conv env u u' _ -> False
- 兩個 universe 當然可以互相轉換(注意這個語言從頭到尾都沒在管 universe level 的問題)
- 兩個 \(\Pi (x:A) \to B\) type 的檢查
- 先看兩個 \(A\) 的部分能不能轉換
- 再看統一套用一個變數
x
能不能讓兩個 \(B\ x\) 轉換 - 兩步驟都成功的話,就可以說這兩個 \(\Pi \) type 可以轉換
- 兩個 lambda 是上面的 \(\Pi \) type 的簡化版,拿掉 \(A\) 的部分就是一樣的
- lambda 跟任意 term 或是任意 term 跟 lambda 這兩種情況是對稱的,這時候可以轉換是指:
VApp u (VVar x)
跟t (VVar x)
可以轉換,當- 擴張 environment 加上
x = VVar x
- 任意 term 寫成
u
- host lambda 寫成
t
- 擴張 environment 加上
- 兩個變數是檢查它們是不是同一個變數
- 兩個卡住值的情況下,把裡面儲存的值拿出來看能不能轉換
- 走到這裡就是不能轉換
輔助程式 [tt-001E]
- November 25, 2022
- Lîm Tsú-thuàn
輔助程式 [tt-001E]
- November 25, 2022
- Lîm Tsú-thuàn
這裡就不再列出全部的列印(printing)跟解析(parsing)相關程式,主要關注對上面的程式有用途的部分。
語言的定義 [tt-001J]
- November 25, 2022
- Lîm Tsú-thuàn
語言的定義 [tt-001J]
- November 25, 2022
- Lîm Tsú-thuàn
原始語言的定義如下
type Name = String type Ty = Tm type Raw = Tm data Tm = Var Name -- x | Lam Name Tm -- \x.t | Tm :@ Tm -- t u | U -- universe | Pi Name Ty Ty -- (x : A) -> B x | Let Name Ty Tm Tm -- let x : A = t; u {- helper -} | SrcPos SourcePos Tm -- annotate source position deriving (Eq)
執行會產出的語言的定義如下,可以看到 lambda 跟 \(\Pi \) 都運用了宿主環境的函數
type VTy = Val data Val = VVar Name | VApp Val ~Val | VLam Name (Val -> Val) | VPi Name Val (Val -> Val) | VU
避免命名衝突 [tt-001K]
- November 25, 2022
- Lîm Tsú-thuàn
避免命名衝突 [tt-001K]
- November 25, 2022
- Lîm Tsú-thuàn
fresh
用在生成臨時變數時,不會引發命名衝突
fresh :: Env -> Name -> Name fresh env "_" = "_" fresh env x = case lookup x env of Just _ -> fresh env (x ++ "'") _ -> x
型別檢查的 monad [tt-001L]
- November 25, 2022
- Lîm Tsú-thuàn
型別檢查的 monad [tt-001L]
- November 25, 2022
- Lîm Tsú-thuàn
型別檢查時,下列的程式定義了檢查時的 monad 跟定位錯誤的工具
type M = Either (String, Maybe SourcePos) report :: String -> M a report s = Left (s, Nothing) addPos :: SourcePos -> M a -> M a addPos pos ma = case ma of Left (msg, Nothing) -> Left (msg, Just pos) ma -> ma
還原與正規化 [tt-001M]
- November 25, 2022
- Lîm Tsú-thuàn
還原與正規化 [tt-001M]
- November 25, 2022
- Lîm Tsú-thuàn
這主要就是為了讓執行完的程式印出來的東西可以看
quote :: Env -> Val -> Tm quote env = \case VVar x -> Var x VApp t u -> quote env t :@ quote env u VLam (fresh env -> x) t -> Lam x $ quote ((x, VVar x) : env) (t (VVar x)) VPi (fresh env -> x) a b -> Pi x (quote env a) $ quote ((x, VVar x) : env) (b (VVar x)) VU -> U nf :: Env -> Tm -> Tm nf env = quote env . eval env
Conclusion. [tt-001N]
- November 25, 2022
- Lîm Tsú-thuàn
Conclusion. [tt-001N]
- November 25, 2022
- Lîm Tsú-thuàn
除了學到 addPos
跟 withPos
的有趣小技巧之外,寫下這篇紀錄也讓我更了解 conversion check 的過程跟各個部件的用途,像是 stuck 的存在跟如何處理,或是 lambda 為什麼不共用 infer
再調用 conv
等等。希望對你也一樣有幫助。
Wasm 實用小技巧 [wasm-0008]
- November 12, 2022
- Lîm Tsú-thuàn
Wasm 實用小技巧 [wasm-0008]
- November 12, 2022
- Lîm Tsú-thuàn
最近工作上的開發,對 wasm 的實務又有了更多的掌握,同時發現 wasm 各種資訊的缺乏。很多技術細節散亂在數十個不同的網頁中,各家編譯器跟 wasm 執行環境又充斥讓人頭痛的小毛病。所以我在這裡記錄下當下各種實用的技巧。
Rust 相關的標記屬性 [wasm-0001]
- November 12, 2022
- Lîm Tsú-thuàn
Rust 相關的標記屬性 [wasm-0001]
- November 12, 2022
- Lîm Tsú-thuàn
Rust 中的各種標記對編寫能用的 wasm module 置關重要,在其他語言很多 wasm 的特性根本用不出來。 這是目前多家編譯器各自實作 wasm 的碎片問題,不是每個語言都能良好的支援新的 wasm proposal。
Example. #![feature(wasm_abi)]
跟 extern "wasm"
[wasm-0002]
- November 12, 2022
- Lîm Tsú-thuàn
Example. #![feature(wasm_abi)]
跟 extern "wasm"
[wasm-0002]
- November 12, 2022
- Lîm Tsú-thuàn
用 #![feature(wasm_abi)]
開啟特性之後,就不會發生回傳複雜型別的 extern function 被改成用 i32
參數的問題。 例如以下程式就不會被修改成 foo(i32) -> ()
,而是正常的 foo() -> i32
。
extern "wasm" { fn foo() -> StructType; }
當然,可以看到還是會被轉成用 i32
表示的指標去傳遞資料,但比之前進步很多。
Example. #[link(wasm_import_module = "mod")]
[wasm-0003]
- November 12, 2022
- Lîm Tsú-thuàn
Example. #[link(wasm_import_module = "mod")]
[wasm-0003]
- November 12, 2022
- Lîm Tsú-thuàn
用 #[link(wasm_import_module = "mod")]
修飾程式的用途是正確的引入其他模組, 舉個範例
#[link(wasm_import_module = "host")] extern "wasm" { fn host_println(str_ptr: *const u8, str_len: usize) -> (); }
用這個標記之後,它就會在 host
尋找 host_println
而不是其他名稱的模組,例如預設的模組 env
。
Example. Custom section [wasm-0004]
- November 12, 2022
- Lîm Tsú-thuàn
Example. Custom section [wasm-0004]
- November 12, 2022
- Lîm Tsú-thuàn
這可以拿來塞任何你想要的資訊,或是拿去當 buffer,缺點是除了 Rust 好像沒有編譯器有要支援。
#[link_section = "hello"] pub static SECTION: [u8; 24] = *b"This is a custom section";
WasmEdge SDK [wasm-0005]
- November 12, 2022
- Lîm Tsú-thuàn
WasmEdge SDK [wasm-0005]
- November 12, 2022
- Lîm Tsú-thuàn
要使用 wasmedge SDK,需要在 Cargo.toml
裡面加上依賴,讓 wasmedge-sys 使用 "*" 是因為兩者有對應,所以還是讓建構工具自己找出合適的依賴就好。
wasmedge-sdk = "0.6.0" wasmedge-sys = "*"
現在專案有了正確的依賴,就可以繼續開發了。
Example. Host function 傳遞字串 [wasm-0006]
- November 12, 2022
- Lîm Tsú-thuàn
Example. Host function 傳遞字串 [wasm-0006]
- November 12, 2022
- Lîm Tsú-thuàn
wasm 一個很實際的需求就是傳遞 non-primitive 的資料型別,在 WasmEdge 裡面做這件事的方法其實沒有完善的文件紀錄。 下面的程式碼是 runtime 設定
fn main() -> Result<(), anyhow::Error> { // 設定需要什麼能力 let config = ConfigBuilder::new(CommonConfigOptions::default()) .with_host_registration_config(HostRegistrationConfigOptions::default().wasi(true)) .build()?; // 建立 import object,語意是從 host 引入名為 host_suffix 的函數 let import = ImportObjectBuilder::new() .with_func::<(i32, i32), (i32, i32), !>("host_suffix", host_suffix, None)? .build("host")?; // 建立 vm 並註冊模組 let vm = Vm::new(Some(config))? .register_import_module(import)? .register_module_from_file("app", "app.wasm")?; // 執行叫做 app 模組中名叫 start 的函數並查看結果 let result = vm.run_func(Some("app"), "start", None)?; println!("result: {}", result[0].to_i32()); }
Host function 的定義如下
#[host_function] fn host_suffix(caller: Caller, input: Vec<WasmValue>) -> Result<Vec<WasmValue>, HostFuncError> { let mut mem = caller.memory(0).unwrap(); let addr = input[0].to_i32() as u32; let size = input[1].to_i32() as u32; let data = mem.read(addr, size).expect("fail to get string"); let mut s = String::from_utf8_lossy(&data).to_string(); s.push_str("_suffix"); // 總之 wasm 模組的記憶體肯定不會用到還不存在的位址 let final_addr = mem.size() + 1; // 繼續增加一個 page size 的區塊 mem.grow(1).expect("fail to grow memory"); // 把要傳回去的字串寫入位址 mem.write(s.as_bytes(), final_addr) .expect("fail to write returned string"); Ok(vec![ // 第一個回傳值是指標 WasmValue::from_i32(final_addr as i32), // 第二個回傳值是長度 WasmValue::from_i32(s.len() as i32), ]) }
在 wasm module 那邊則是寫
#![feature(wasm_abi)] #[repr(C)] struct HostString { ptr: *mut u8, size: usize, } #[link(wasm_import_module = "host")] extern "wasm" { fn host_suffix(str_ptr: *const u8, str_len: usize) -> HostString; } #[no_mangle] pub fn start() -> u32 { let s = "hello"; let s2 = unsafe { let HostString { ptr, size } = host_suffix(s.as_ptr(), s.len()); String::from_raw_parts(ptr, size, size) }; s2.len() as u32 }
可以看到 extern "wasm"
裡面 HostString
可以自動從 multi-values 復原回來。
做這個實驗的時候還發生了小插曲,我跟同事發現host_function
其實沒有正確的遵循 modifier, 所以即使你寫#[host_function] pub fn
它還是會把函數變成 private 的。
Example. Host function 存取 vm
中的 wasm module instance [wasm-0007]
- November 12, 2022
- Lîm Tsú-thuàn
Example. Host function 存取 vm
中的 wasm module instance [wasm-0007]
- November 12, 2022
- Lîm Tsú-thuàn
let cvm = Box::new(vm.clone()); let import = ImportObjectBuilder::new() .with_func::<(i32, i32), (), !>( "grow_module_memory", move |caller: CallingFrame, input: Vec<WasmValue>, _: *mut c_void| -> Result<Vec<WasmValue>, HostFuncError> { let mod_name = load_string(caller, input[0].to_i32() as u32, input[1].to_i32() as u32); let target_mod = cvm.to_owned().named_module(mod_name).unwrap(); // memory 這個名字是 LLVM 預設的生成結果 target_mod.memory("memory").unwrap().grow(1); Ok(vec![]) }, None, )?
因為不能試圖移動 vm
,只好複製出來使用。
因為又一個插曲, 所以雖然這個技巧理論上能呼叫另一個註冊模組的函數,但目前功能是殘廢的。
Conclusion. 混亂的標準支援 [wasm-0009]
- November 12, 2022
- Lîm Tsú-thuàn
Conclusion. 混亂的標準支援 [wasm-0009]
- November 12, 2022
- Lîm Tsú-thuàn
總之,這團混亂最大的問題在於 wasm proposal 對實作的要求太少,比如說宣告軟體是否符合標準。也因此支援度混亂不一,各家編譯器跟執行環境都可以喊說自己有支援,但你頭洗下去才發現其實有很多平台特定的要求跟限制。當然反過來說這表示 wasm 正在蓬勃發展,很多有用的規範正在推進,希望能夠給大家帶來更多的功能。
Mark sweep GC [cs-000F]
- September 3, 2018
- Lîm Tsú-thuàn
Mark sweep GC [cs-000F]
- September 3, 2018
- Lîm Tsú-thuàn
Mark-Sweep is a classic GC algorithm, it's combined with two parts, mark and sweep.
mark(root): if not marked?(root): mark(root) for obj in knowns(root): mark(obj)
sweep(heap): for obj in heap: if marked?(obj): unmark(obj) else: release(obj)
If we run collection
(mark-sweep), then since each object is reachable from root
, so no one would be released.
After do some executions, obj1
don't need obj3
anymore, so it became:
Now when we run collection
, obj3
is unreachable from root, so it won't be marked! When running to sweep, it will be dropped.
Polarized-system-f [org-0002]
- July 22, 2023
- Lîm Tsú-thuàn
- 2023-07-22-polarized-system-f.html
Polarized-system-f [org-0002]
- July 22, 2023
- Lîm Tsú-thuàn
- 2023-07-22-polarized-system-f.html
High-performance-graph [org-0004]
- June 28, 2023
- Lîm Tsú-thuàn
- 2023-06-28-high-performance-graph.html
High-performance-graph [org-0004]
- June 28, 2023
- Lîm Tsú-thuàn
- 2023-06-28-high-performance-graph.html
Recur-interpreter [org-0005]
- June 22, 2023
- Lîm Tsú-thuàn
- 2023-06-22-recur-interpreter.html
Recur-interpreter [org-0005]
- June 22, 2023
- Lîm Tsú-thuàn
- 2023-06-22-recur-interpreter.html
Arm64-store-load [org-0009]
- June 4, 2023
- Lîm Tsú-thuàn
- 2023-06-04-arm64-store-load.html
Arm64-store-load [org-0009]
- June 4, 2023
- Lîm Tsú-thuàn
- 2023-06-04-arm64-store-load.html
Dafny-lang [org-000B]
- May 17, 2023
- Lîm Tsú-thuàn
- 2023-05-17-dafny-lang.html
Dafny-lang [org-000B]
- May 17, 2023
- Lîm Tsú-thuàn
- 2023-05-17-dafny-lang.html
The-power-of-oop-and-abstraction [org-000D]
The-power-of-oop-and-abstraction [org-000D]
Pythagorean-triples [org-000E]
- April 16, 2023
- Lîm Tsú-thuàn
- 2023-04-16-pythagorean-triples.html
Pythagorean-triples [org-000E]
- April 16, 2023
- Lîm Tsú-thuàn
- 2023-04-16-pythagorean-triples.html
[PL] STLC 的 categorical semantic [org-000H]
- March 16, 2023
- Lîm Tsú-thuàn
- 2023-03-16-stlc-categorial-semantic.html
[PL] STLC 的 categorical semantic [org-000H]
- March 16, 2023
- Lîm Tsú-thuàn
- 2023-03-16-stlc-categorial-semantic.html
Prime-inf-topology [org-000I]
- March 7, 2023
- Lîm Tsú-thuàn
- 2023-03-07-prime-inf-topology.html
Prime-inf-topology [org-000I]
- March 7, 2023
- Lîm Tsú-thuàn
- 2023-03-07-prime-inf-topology.html
Genetic-algorithm [org-000L]
- January 31, 2023
- Lîm Tsú-thuàn
- 2023-01-31-genetic-algorithm.html
Genetic-algorithm [org-000L]
- January 31, 2023
- Lîm Tsú-thuàn
- 2023-01-31-genetic-algorithm.html
Idris2-nix [org-000M]
- January 1, 2023
- Lîm Tsú-thuàn
- 2023-01-01-idris2-nix.html
Idris2-nix [org-000M]
- January 1, 2023
- Lîm Tsú-thuàn
- 2023-01-01-idris2-nix.html
Note: resource algebra [org-000O]
- December 19, 2022
- Lîm Tsú-thuàn
- 2022-12-19-note-resource.html
Note: resource algebra [org-000O]
- December 19, 2022
- Lîm Tsú-thuàn
- 2022-12-19-note-resource.html
Gcd [org-000P]
- December 9, 2022
- Lîm Tsú-thuàn
- 2022-12-09-gcd.html
Gcd [org-000P]
- December 9, 2022
- Lîm Tsú-thuàn
- 2022-12-09-gcd.html
Rust-wasm-abi [org-000Q]
- December 8, 2022
- Lîm Tsú-thuàn
- 2022-12-08-rust-wasm-abi.html
Rust-wasm-abi [org-000Q]
- December 8, 2022
- Lîm Tsú-thuàn
- 2022-12-08-rust-wasm-abi.html
Concurrent-functional-programming [org-000R]
- December 7, 2022
- Lîm Tsú-thuàn
- 2022-12-07-concurrent-functional-programming.html
Concurrent-functional-programming [org-000R]
- December 7, 2022
- Lîm Tsú-thuàn
- 2022-12-07-concurrent-functional-programming.html
Pos-annotation [org-000S]
- December 6, 2022
- Lîm Tsú-thuàn
- 2022-12-06-pos-annotation.html
Pos-annotation [org-000S]
- December 6, 2022
- Lîm Tsú-thuàn
- 2022-12-06-pos-annotation.html
Note-hls-m1-problem [org-000U]
- November 30, 2022
- Lîm Tsú-thuàn
- 2022-11-30-note-hls-m1-problem.html
Note-hls-m1-problem [org-000U]
- November 30, 2022
- Lîm Tsú-thuàn
- 2022-11-30-note-hls-m1-problem.html
Induction-proof-operation [org-000W]
- November 20, 2022
- Lîm Tsú-thuàn
- 2022-11-20-induction-proof-operation.html
Induction-proof-operation [org-000W]
- November 20, 2022
- Lîm Tsú-thuàn
- 2022-11-20-induction-proof-operation.html
Layering [org-0011]
- November 3, 2022
- Lîm Tsú-thuàn
- 2022-11-03-layering.html
Layering [org-0011]
- November 3, 2022
- Lîm Tsú-thuàn
- 2022-11-03-layering.html
Polymorphism-in-runtime [org-0010]
- November 3, 2022
- Lîm Tsú-thuàn
- 2022-11-03-polymorphism-in-runtime.html
Polymorphism-in-runtime [org-0010]
- November 3, 2022
- Lîm Tsú-thuàn
- 2022-11-03-polymorphism-in-runtime.html
Leftist-tree [org-0013]
- October 30, 2022
- Lîm Tsú-thuàn
- 2022-10-30-leftist-tree.html
Leftist-tree [org-0013]
- October 30, 2022
- Lîm Tsú-thuàn
- 2022-10-30-leftist-tree.html
Note-effect-system-koka [org-0015]
- October 18, 2022
- Lîm Tsú-thuàn
- 2022-10-18-note-effect-system-koka.html
Note-effect-system-koka [org-0015]
- October 18, 2022
- Lîm Tsú-thuàn
- 2022-10-18-note-effect-system-koka.html
Note-product [org-0014]
- October 18, 2022
- Lîm Tsú-thuàn
- 2022-10-18-note-product.html
Note-product [org-0014]
- October 18, 2022
- Lîm Tsú-thuàn
- 2022-10-18-note-product.html
Picopass [org-0017]
- September 17, 2022
- Lîm Tsú-thuàn
- 2022-09-17-picopass.html
Picopass [org-0017]
- September 17, 2022
- Lîm Tsú-thuàn
- 2022-09-17-picopass.html
Practical-de-bruijn [org-0019]
- September 4, 2022
- Lîm Tsú-thuàn
- 2022-09-04-practical-de-bruijn.html
Practical-de-bruijn [org-0019]
- September 4, 2022
- Lîm Tsú-thuàn
- 2022-09-04-practical-de-bruijn.html
Ref-eq [org-0018]
- September 4, 2022
- Lîm Tsú-thuàn
- 2022-09-04-ref-eq.html
Ref-eq [org-0018]
- September 4, 2022
- Lîm Tsú-thuàn
- 2022-09-04-ref-eq.html
Racket-future [org-001A]
- September 3, 2022
- Lîm Tsú-thuàn
- 2022-09-03-racket-future.html
Racket-future [org-001A]
- September 3, 2022
- Lîm Tsú-thuàn
- 2022-09-03-racket-future.html
Dependent-type [org-001B]
- September 1, 2022
- Lîm Tsú-thuàn
- 2022-09-01-dependent-type.html
Dependent-type [org-001B]
- September 1, 2022
- Lîm Tsú-thuàn
- 2022-09-01-dependent-type.html
Ee-lib [org-001C]
- August 28, 2022
- Lîm Tsú-thuàn
- 2022-08-28-ee-lib.html
Ee-lib [org-001C]
- August 28, 2022
- Lîm Tsú-thuàn
- 2022-08-28-ee-lib.html
Typed-racket-intro [org-001D]
- August 19, 2022
- Lîm Tsú-thuàn
- 2022-08-19-typed-racket-intro.html
Typed-racket-intro [org-001D]
- August 19, 2022
- Lîm Tsú-thuàn
- 2022-08-19-typed-racket-intro.html
Racket-preference-test [org-001E]
- August 4, 2022
- Lîm Tsú-thuàn
- 2022-08-04-racket-preference-test.html
Racket-preference-test [org-001E]
- August 4, 2022
- Lîm Tsú-thuàn
- 2022-08-04-racket-preference-test.html
Sauron-dev-log [org-001F]
- July 25, 2022
- Lîm Tsú-thuàn
- 2022-07-25-sauron-dev-log.html
Sauron-dev-log [org-001F]
- July 25, 2022
- Lîm Tsú-thuàn
- 2022-07-25-sauron-dev-log.html
Leibniz-product-rule [org-001J]
- June 30, 2022
- Lîm Tsú-thuàn
- 2022-06-30-leibniz-product-rule.html
Leibniz-product-rule [org-001J]
- June 30, 2022
- Lîm Tsú-thuàn
- 2022-06-30-leibniz-product-rule.html
Set-theoretic-type-difference [org-001K]
- June 28, 2022
- Lîm Tsú-thuàn
- 2022-06-28-set-theoretic-type-difference.html
Set-theoretic-type-difference [org-001K]
- June 28, 2022
- Lîm Tsú-thuàn
- 2022-06-28-set-theoretic-type-difference.html
Common-patterns-in-nanopass [org-001L]
- June 16, 2022
- Lîm Tsú-thuàn
- 2022-06-16-common-patterns-in-nanopass.html
Common-patterns-in-nanopass [org-001L]
- June 16, 2022
- Lîm Tsú-thuàn
- 2022-06-16-common-patterns-in-nanopass.html
Riemann-integral [org-001M]
- June 3, 2022
- Lîm Tsú-thuàn
- 2022-06-03-riemann-integral.html
Riemann-integral [org-001M]
- June 3, 2022
- Lîm Tsú-thuàn
- 2022-06-03-riemann-integral.html
Closure-conversion [org-001N]
- March 21, 2022
- Lîm Tsú-thuàn
- 2022-03-21-closure-conversion.html
Closure-conversion [org-001N]
- March 21, 2022
- Lîm Tsú-thuàn
- 2022-03-21-closure-conversion.html
Ordered-field [org-001O]
- March 4, 2022
- Lîm Tsú-thuàn
- 2022-03-04-ordered-field.html
Ordered-field [org-001O]
- March 4, 2022
- Lîm Tsú-thuàn
- 2022-03-04-ordered-field.html
64Bits-encoding [org-001P]
- February 19, 2022
- Lîm Tsú-thuàn
- 2022-02-19-64bits-encoding.html
64Bits-encoding [org-001P]
- February 19, 2022
- Lîm Tsú-thuàn
- 2022-02-19-64bits-encoding.html
Macro [org-001T]
- January 30, 2022
- Lîm Tsú-thuàn
- 2022-01-30-macro.html
Macro [org-001T]
- January 30, 2022
- Lîm Tsú-thuàn
- 2022-01-30-macro.html
Ssh-to-my-nixos [org-001U]
- January 21, 2022
- Lîm Tsú-thuàn
- 2022-01-21-ssh-to-my-nixos.html
Ssh-to-my-nixos [org-001U]
- January 21, 2022
- Lîm Tsú-thuàn
- 2022-01-21-ssh-to-my-nixos.html
Chez-scheme-and-lib [org-001Z]
- January 14, 2022
- Lîm Tsú-thuàn
- 2022-01-14-chez-scheme-and-lib.html
Chez-scheme-and-lib [org-001Z]
- January 14, 2022
- Lîm Tsú-thuàn
- 2022-01-14-chez-scheme-and-lib.html
Arduino-zig-7-seg-display [org-0021]
- January 10, 2022
- Lîm Tsú-thuàn
- 2022-01-10-arduino-zig-7-seg-display.html
Arduino-zig-7-seg-display [org-0021]
- January 10, 2022
- Lîm Tsú-thuàn
- 2022-01-10-arduino-zig-7-seg-display.html
Forth-aarch64 [org-0022]
- January 8, 2022
- Lîm Tsú-thuàn
- 2022-01-08-forth-aarch64.html
Forth-aarch64 [org-0022]
- January 8, 2022
- Lîm Tsú-thuàn
- 2022-01-08-forth-aarch64.html
Note-nix-command [org-0024]
- January 6, 2022
- Lîm Tsú-thuàn
- 2022-01-06-note-nix-command.html
Note-nix-command [org-0024]
- January 6, 2022
- Lîm Tsú-thuàn
- 2022-01-06-note-nix-command.html
Arduino-zig-blink [org-0025]
- January 4, 2022
- Lîm Tsú-thuàn
- 2022-01-04-arduino-zig-blink.html
Arduino-zig-blink [org-0025]
- January 4, 2022
- Lîm Tsú-thuàn
- 2022-01-04-arduino-zig-blink.html
Julia-macrotools [org-0027]
- December 11, 2021
- Lîm Tsú-thuàn
- 2021-12-11-julia-macrotools.html
Julia-macrotools [org-0027]
- December 11, 2021
- Lîm Tsú-thuàn
- 2021-12-11-julia-macrotools.html
Invent-rectangle-area-formula [org-0029]
- October 8, 2021
- Lîm Tsú-thuàn
- 2021-10-08-invent-rectangle-area-formula.html
Invent-rectangle-area-formula [org-0029]
- October 8, 2021
- Lîm Tsú-thuàn
- 2021-10-08-invent-rectangle-area-formula.html
Syntax-property-and-local-expand [org-002B]
- August 19, 2021
- Lîm Tsú-thuàn
- 2021-08-19-syntax-property-and-local-expand.html
Syntax-property-and-local-expand [org-002B]
- August 19, 2021
- Lîm Tsú-thuàn
- 2021-08-19-syntax-property-and-local-expand.html
Elixir-with [org-002C]
- July 17, 2021
- Lîm Tsú-thuàn
- 2021-07-17-elixir-with.html
Elixir-with [org-002C]
- July 17, 2021
- Lîm Tsú-thuàn
- 2021-07-17-elixir-with.html
Elixir-phoenix-graphql [org-002F]
- July 6, 2021
- Lîm Tsú-thuàn
- 2021-07-06-elixir-phoenix-graphql.html
Elixir-phoenix-graphql [org-002F]
- July 6, 2021
- Lîm Tsú-thuàn
- 2021-07-06-elixir-phoenix-graphql.html
Find-max-subsubsquence [org-002G]
- July 3, 2021
- Lîm Tsú-thuàn
- 2021-07-03-find-max-subsubsquence.html
Find-max-subsubsquence [org-002G]
- July 3, 2021
- Lîm Tsú-thuàn
- 2021-07-03-find-max-subsubsquence.html
Vscode-remote-pack [org-002H]
- June 18, 2021
- Lîm Tsú-thuàn
- 2021-06-18-vscode-remote-pack.html
Vscode-remote-pack [org-002H]
- June 18, 2021
- Lîm Tsú-thuàn
- 2021-06-18-vscode-remote-pack.html
Lexer-and-parser [org-002I]
- June 4, 2021
- Lîm Tsú-thuàn
- 2021-06-04-lexer-and-parser.html
Lexer-and-parser [org-002I]
- June 4, 2021
- Lîm Tsú-thuàn
- 2021-06-04-lexer-and-parser.html
Sexp-macro-and-develop [org-002J]
- May 11, 2021
- Lîm Tsú-thuàn
- 2021-05-11-sexp-macro-and-develop.html
Sexp-macro-and-develop [org-002J]
- May 11, 2021
- Lîm Tsú-thuàn
- 2021-05-11-sexp-macro-and-develop.html
Strictly positive check [org-002K]
- May 2, 2021
- Lîm Tsú-thuàn
- 2021-05-02-strictly-positive-check.html
Strictly positive check [org-002K]
- May 2, 2021
- Lîm Tsú-thuàn
- 2021-05-02-strictly-positive-check.html
Un-delimited-continuation [org-002N]
- March 13, 2021
- Lîm Tsú-thuàn
- 2021-03-13-un-delimited-continuation.html
Un-delimited-continuation [org-002N]
- March 13, 2021
- Lîm Tsú-thuàn
- 2021-03-13-un-delimited-continuation.html
Sphere-is-convex [org-002O]
- March 10, 2021
- Lîm Tsú-thuàn
- 2021-03-10-sphere-is-convex.html
Sphere-is-convex [org-002O]
- March 10, 2021
- Lîm Tsú-thuàn
- 2021-03-10-sphere-is-convex.html
Note-nix-home-manager [org-002Q]
- February 12, 2021
- Lîm Tsú-thuàn
- 2021-02-12-note-nix-home-manager.html
Note-nix-home-manager [org-002Q]
- February 12, 2021
- Lîm Tsú-thuàn
- 2021-02-12-note-nix-home-manager.html
Nixos-install [org-002R]
- February 4, 2021
- Lîm Tsú-thuàn
- 2021-02-04-nixos-install.html
Nixos-install [org-002R]
- February 4, 2021
- Lîm Tsú-thuàn
- 2021-02-04-nixos-install.html
Summary [org-002S]
- January 29, 2021
- Lîm Tsú-thuàn
- 2021-01-29-summary.html
Summary [org-002S]
- January 29, 2021
- Lîm Tsú-thuàn
- 2021-01-29-summary.html
Installation [org-002T]
- January 19, 2021
- Lîm Tsú-thuàn
- 2021-01-19-installation.html
Installation [org-002T]
- January 19, 2021
- Lîm Tsú-thuàn
- 2021-01-19-installation.html
Termination-check [org-002U]
- January 13, 2021
- Lîm Tsú-thuàn
- 2021-01-13-termination-check.html
Termination-check [org-002U]
- January 13, 2021
- Lîm Tsú-thuàn
- 2021-01-13-termination-check.html
Subtle-racket-macro [org-002V]
- January 7, 2021
- Lîm Tsú-thuàn
- 2021-01-07-subtle-racket-macro.html
Subtle-racket-macro [org-002V]
- January 7, 2021
- Lîm Tsú-thuàn
- 2021-01-07-subtle-racket-macro.html
Imperative-semantic [org-002W]
- December 22, 2020
- Lîm Tsú-thuàn
- 2020-12-22-imperative-semantic.html
Imperative-semantic [org-002W]
- December 22, 2020
- Lîm Tsú-thuàn
- 2020-12-22-imperative-semantic.html
Recommend-books [org-002X]
- December 20, 2020
- Lîm Tsú-thuàn
- 2020-12-20-recommend-books.html
Recommend-books [org-002X]
- December 20, 2020
- Lîm Tsú-thuàn
- 2020-12-20-recommend-books.html
Is-an-oop-square-ra-rectangle [org-002Z]
- November 16, 2020
- Lîm Tsú-thuàn
- 2020-11-16-is-an-oop-square-ra-rectangle.html
Is-an-oop-square-ra-rectangle [org-002Z]
- November 16, 2020
- Lîm Tsú-thuàn
- 2020-11-16-is-an-oop-square-ra-rectangle.html
Summary [org-002Y]
- November 16, 2020
- Lîm Tsú-thuàn
- 2020-11-16-summary.html
Summary [org-002Y]
- November 16, 2020
- Lîm Tsú-thuàn
- 2020-11-16-summary.html
Note-lambda-cube [org-0030]
- September 17, 2020
- Lîm Tsú-thuàn
- 2020-09-17-note-lambda-cube.html
Note-lambda-cube [org-0030]
- September 17, 2020
- Lîm Tsú-thuàn
- 2020-09-17-note-lambda-cube.html
Scribble-and-xelatex [org-0031]
- September 1, 2020
- Lîm Tsú-thuàn
- 2020-09-01-scribble-and-xelatex.html
Scribble-and-xelatex [org-0031]
- September 1, 2020
- Lîm Tsú-thuàn
- 2020-09-01-scribble-and-xelatex.html
Racket-macro-define-where [org-0032]
- August 23, 2020
- Lîm Tsú-thuàn
- 2020-08-23-racket-macro-define-where.html
Racket-macro-define-where [org-0032]
- August 23, 2020
- Lîm Tsú-thuàn
- 2020-08-23-racket-macro-define-where.html
Note-coq-tactics [org-0033]
- August 19, 2020
- Lîm Tsú-thuàn
- 2020-08-19-note-coq-tactics.html
Note-coq-tactics [org-0033]
- August 19, 2020
- Lîm Tsú-thuàn
- 2020-08-19-note-coq-tactics.html
Infinite-how-big [org-0034]
- August 7, 2020
- Lîm Tsú-thuàn
- 2020-08-07-infinite-how-big.html
Infinite-how-big [org-0034]
- August 7, 2020
- Lîm Tsú-thuàn
- 2020-08-07-infinite-how-big.html
Note-bad-idea-s-exp-haskell [org-0036]
- July 31, 2020
- Lîm Tsú-thuàn
- 2020-07-31-note-bad-idea-s-exp-haskell.html
Note-bad-idea-s-exp-haskell [org-0036]
- July 31, 2020
- Lîm Tsú-thuàn
- 2020-07-31-note-bad-idea-s-exp-haskell.html
Note-racket-gui-framework-and-editor [org-0037]
Note-racket-gui-framework-and-editor [org-0037]
How-to-find-mk-fixed-point [org-0038]
- July 26, 2020
- Lîm Tsú-thuàn
- 2020-07-26-how-to-find-mk-fixed-point.html
How-to-find-mk-fixed-point [org-0038]
- July 26, 2020
- Lîm Tsú-thuàn
- 2020-07-26-how-to-find-mk-fixed-point.html
Why-logic-programming [org-0039]
- July 15, 2020
- Lîm Tsú-thuàn
- 2020-07-15-why-logic-programming.html
Why-logic-programming [org-0039]
- July 15, 2020
- Lîm Tsú-thuàn
- 2020-07-15-why-logic-programming.html
Recommend-novel-quality-land [org-003B]
Recommend-novel-quality-land [org-003B]
Algorithm-order [org-003C]
- June 20, 2020
- Lîm Tsú-thuàn
- 2020-06-20-algorithm-order.html
Algorithm-order [org-003C]
- June 20, 2020
- Lîm Tsú-thuàn
- 2020-06-20-algorithm-order.html
Recipe-okonomiyaki [org-003D]
- June 17, 2020
- Lîm Tsú-thuàn
- 2020-06-17-recipe-okonomiyaki.html
Recipe-okonomiyaki [org-003D]
- June 17, 2020
- Lîm Tsú-thuàn
- 2020-06-17-recipe-okonomiyaki.html
Note-zfc [org-003F]
- June 11, 2020
- Lîm Tsú-thuàn
- 2020-06-11-note-zfc.html
Note-zfc [org-003F]
- June 11, 2020
- Lîm Tsú-thuàn
- 2020-06-11-note-zfc.html
Currying [org-003I]
- May 31, 2020
- Lîm Tsú-thuàn
- 2020-05-31-currying.html
Currying [org-003I]
- May 31, 2020
- Lîm Tsú-thuàn
- 2020-05-31-currying.html
Set-theory-three-paradox [org-003H]
- May 31, 2020
- Lîm Tsú-thuàn
- 2020-05-31-set-theory-three-paradox.html
Set-theory-three-paradox [org-003H]
- May 31, 2020
- Lîm Tsú-thuàn
- 2020-05-31-set-theory-three-paradox.html
Hindley-milner-system-incremental-build-and-make-new-language [org-003J]
Hindley-milner-system-incremental-build-and-make-new-language [org-003J]
De-bruijn-index [org-003K]
- May 16, 2020
- Lîm Tsú-thuàn
- 2020-05-16-de-bruijn-index.html
De-bruijn-index [org-003K]
- May 16, 2020
- Lîm Tsú-thuàn
- 2020-05-16-de-bruijn-index.html
Programming-life-retro [org-003L]
- May 13, 2020
- Lîm Tsú-thuàn
- 2020-05-13-programming-life-retro.html
Programming-life-retro [org-003L]
- May 13, 2020
- Lîm Tsú-thuàn
- 2020-05-13-programming-life-retro.html
Algorithm-time-complexity [org-003M]
- May 12, 2020
- Lîm Tsú-thuàn
- 2020-05-12-algorithm-time-complexity.html
Algorithm-time-complexity [org-003M]
- May 12, 2020
- Lîm Tsú-thuàn
- 2020-05-12-algorithm-time-complexity.html
Spaghetti [org-003N]
- May 10, 2020
- Lîm Tsú-thuàn
- 2020-05-10-spaghetti.html
Spaghetti [org-003N]
- May 10, 2020
- Lîm Tsú-thuàn
- 2020-05-10-spaghetti.html
A-beautiful-proof-there-have-infinite-primes [org-003O]
A-beautiful-proof-there-have-infinite-primes [org-003O]
How-to-parse-expression-with-parser-combinator [org-003P]
How-to-parse-expression-with-parser-combinator [org-003P]
Abstraction-of-programming-design-2-user-interface [org-003Q]
Abstraction-of-programming-design-2-user-interface [org-003Q]
Note-how-to-install-nix-on-macos-catalina [org-003R]
Note-how-to-install-nix-on-macos-catalina [org-003R]
Note-cpp-member-initialize-order [org-003S]
- April 13, 2020
- Lîm Tsú-thuàn
- 2020-04-13-note-cpp-member-initialize-order.html
Note-cpp-member-initialize-order [org-003S]
- April 13, 2020
- Lîm Tsú-thuàn
- 2020-04-13-note-cpp-member-initialize-order.html
From-functor-to-applicative [org-003T]
- April 11, 2020
- Lîm Tsú-thuàn
- 2020-04-11-from-functor-to-applicative.html
From-functor-to-applicative [org-003T]
- April 11, 2020
- Lîm Tsú-thuàn
- 2020-04-11-from-functor-to-applicative.html
Note-seven-bridges-of-konigsberg-eulerian-path [org-003U]
Note-seven-bridges-of-konigsberg-eulerian-path [org-003U]
Recommend-novel-skyward [org-003V]
- April 1, 2020
- Lîm Tsú-thuàn
- 2020-04-01-recommend-novel-skyward.html
Recommend-novel-skyward [org-003V]
- April 1, 2020
- Lîm Tsú-thuàn
- 2020-04-01-recommend-novel-skyward.html
Binary-encoding-of-interger [org-003W]
- March 21, 2020
- Lîm Tsú-thuàn
- 2020-03-21-binary-encoding-of-interger.html
Binary-encoding-of-interger [org-003W]
- March 21, 2020
- Lîm Tsú-thuàn
- 2020-03-21-binary-encoding-of-interger.html
A-racket-macro-tutorial-get-http-parameters-easier [org-003Y]
A-racket-macro-tutorial-get-http-parameters-easier [org-003Y]
Suggested-languages [org-003Z]
- February 6, 2020
- Lîm Tsú-thuàn
- 2020-02-06-suggested-languages.html
Suggested-languages [org-003Z]
- February 6, 2020
- Lîm Tsú-thuàn
- 2020-02-06-suggested-languages.html
Last-time-complain-about-go [org-0043]
- January 19, 2020
- Lîm Tsú-thuàn
- 2020-01-19-last-time-complain-about-go.html
Last-time-complain-about-go [org-0043]
- January 19, 2020
- Lîm Tsú-thuàn
- 2020-01-19-last-time-complain-about-go.html
Type-as-constraint-why-we-need-more-type [org-0044]
- January 16, 2020
- Lîm Tsú-thuàn
- 2020-01-16-type-as-constraint-why-we-need-more-type.html
Type-as-constraint-why-we-need-more-type [org-0044]
- January 16, 2020
- Lîm Tsú-thuàn
- 2020-01-16-type-as-constraint-why-we-need-more-type.html
Note-what-is-lambda-calculus [org-0047]
- January 1, 2020
- Lîm Tsú-thuàn
- 2020-01-01-note-what-is-lambda-calculus.html
Note-what-is-lambda-calculus [org-0047]
- January 1, 2020
- Lîm Tsú-thuàn
- 2020-01-01-note-what-is-lambda-calculus.html
Interaction-with-c-in-zig [org-0048]
- December 22, 2019
- Lîm Tsú-thuàn
- 2019-12-22-interaction-with-c-in-zig.html
Interaction-with-c-in-zig [org-0048]
- December 22, 2019
- Lîm Tsú-thuàn
- 2019-12-22-interaction-with-c-in-zig.html
Note-get-labels-from-pod [org-0049]
- December 20, 2019
- Lîm Tsú-thuàn
- 2019-12-20-note-get-labels-from-pod.html
Note-get-labels-from-pod [org-0049]
- December 20, 2019
- Lîm Tsú-thuàn
- 2019-12-20-note-get-labels-from-pod.html
From-infinite-type-to-functor [org-004C]
- December 13, 2019
- Lîm Tsú-thuàn
- 2019-12-13-from-infinite-type-to-functor.html
From-infinite-type-to-functor [org-004C]
- December 13, 2019
- Lîm Tsú-thuàn
- 2019-12-13-from-infinite-type-to-functor.html
Infinite-type [org-004D]
- December 8, 2019
- Lîm Tsú-thuàn
- 2019-12-08-infinite-type.html
Infinite-type [org-004D]
- December 8, 2019
- Lîm Tsú-thuàn
- 2019-12-08-infinite-type.html
Mergeable-replicated-data-types [org-004G]
- November 30, 2019
- Lîm Tsú-thuàn
- 2019-11-30-mergeable-replicated-data-types.html
Mergeable-replicated-data-types [org-004G]
- November 30, 2019
- Lîm Tsú-thuàn
- 2019-11-30-mergeable-replicated-data-types.html
Abstraction-of-programming-design [org-004J]
- November 9, 2019
- Lîm Tsú-thuàn
- 2019-11-09-abstraction-of-programming-design.html
Abstraction-of-programming-design [org-004J]
- November 9, 2019
- Lîm Tsú-thuàn
- 2019-11-09-abstraction-of-programming-design.html
How-to-use-gitignore [org-004K]
- November 8, 2019
- Lîm Tsú-thuàn
- 2019-11-08-how-to-use-gitignore.html
How-to-use-gitignore [org-004K]
- November 8, 2019
- Lîm Tsú-thuàn
- 2019-11-08-how-to-use-gitignore.html
Weird-behavior-gob [org-004L]
- October 31, 2019
- Lîm Tsú-thuàn
- 2019-10-31-weird-behavior-gob.html
Weird-behavior-gob [org-004L]
- October 31, 2019
- Lîm Tsú-thuàn
- 2019-10-31-weird-behavior-gob.html
Dpdk-usertools-devbind [org-004M]
- October 19, 2019
- Lîm Tsú-thuàn
- 2019-10-19-dpdk-usertools-devbind.html
Dpdk-usertools-devbind [org-004M]
- October 19, 2019
- Lîm Tsú-thuàn
- 2019-10-19-dpdk-usertools-devbind.html
Dpdk-input-output-error [org-004N]
- October 18, 2019
- Lîm Tsú-thuàn
- 2019-10-18-dpdk-input-output-error.html
Dpdk-input-output-error [org-004N]
- October 18, 2019
- Lîm Tsú-thuàn
- 2019-10-18-dpdk-input-output-error.html
Nix-report [org-004P]
- September 12, 2019
- Lîm Tsú-thuàn
- 2019-09-12-nix-report.html
Nix-report [org-004P]
- September 12, 2019
- Lîm Tsú-thuàn
- 2019-09-12-nix-report.html
Privileged-pod [org-004Q]
- September 1, 2019
- Lîm Tsú-thuàn
- 2019-09-01-privileged-pod.html
Privileged-pod [org-004Q]
- September 1, 2019
- Lîm Tsú-thuàn
- 2019-09-01-privileged-pod.html
Cgo-can-be-a-trouble [org-004R]
- August 15, 2019
- Lîm Tsú-thuàn
- 2019-08-15-cgo-can-be-a-trouble.html
Cgo-can-be-a-trouble [org-004R]
- August 15, 2019
- Lîm Tsú-thuàn
- 2019-08-15-cgo-can-be-a-trouble.html
Ruby-conf-taiwan-2019 [org-004S]
- August 13, 2019
- Lîm Tsú-thuàn
- 2019-08-13-ruby-conf-taiwan-2019.html
Ruby-conf-taiwan-2019 [org-004S]
- August 13, 2019
- Lîm Tsú-thuàn
- 2019-08-13-ruby-conf-taiwan-2019.html
How-lifetime-trait-can-be-trouble-and-how-to-fix-it [org-004T]
How-lifetime-trait-can-be-trouble-and-how-to-fix-it [org-004T]
Tcpdump-cheat-sheet [org-004U]
- June 25, 2019
- Lîm Tsú-thuàn
- 2019-06-25-tcpdump-cheat-sheet.html
Tcpdump-cheat-sheet [org-004U]
- June 25, 2019
- Lîm Tsú-thuàn
- 2019-06-25-tcpdump-cheat-sheet.html
Simple-way-to-ensure-go-interface-wont-be-implement-accidently [org-004V]
Simple-way-to-ensure-go-interface-wont-be-implement-accidently [org-004V]
Golang-concurrency-bug-i-made [org-004W]
Golang-concurrency-bug-i-made [org-004W]
Kubernetes-networking-concept-and-overview [org-004X]
Kubernetes-networking-concept-and-overview [org-004X]
Hugepages-on-kubernetes [org-004Y]
- May 4, 2019
- Lîm Tsú-thuàn
- 2019-05-04-hugepages-on-kubernetes.html
Hugepages-on-kubernetes [org-004Y]
- May 4, 2019
- Lîm Tsú-thuàn
- 2019-05-04-hugepages-on-kubernetes.html
Five-tools-for-file-transfer [org-004Z]
- April 27, 2019
- Lîm Tsú-thuàn
- 2019-04-27-five-tools-for-file-transfer.html
Five-tools-for-file-transfer [org-004Z]
- April 27, 2019
- Lîm Tsú-thuàn
- 2019-04-27-five-tools-for-file-transfer.html
Grpc-proxy-approach-and-pain [org-0050]
- April 13, 2019
- Lîm Tsú-thuàn
- 2019-04-13-grpc-proxy-approach-and-pain.html
Grpc-proxy-approach-and-pain [org-0050]
- April 13, 2019
- Lîm Tsú-thuàn
- 2019-04-13-grpc-proxy-approach-and-pain.html
Dedekind-cut-and-application [org-0054]
- March 1, 2019
- Lîm Tsú-thuàn
- 2019-03-01-dedekind-cut-and-application.html
Dedekind-cut-and-application [org-0054]
- March 1, 2019
- Lîm Tsú-thuàn
- 2019-03-01-dedekind-cut-and-application.html
Kube-client-go-source-code-tracing [org-0055]
- January 25, 2019
- Lîm Tsú-thuàn
- 2019-01-25-kube-client-go-source-code-tracing.html
Kube-client-go-source-code-tracing [org-0055]
- January 25, 2019
- Lîm Tsú-thuàn
- 2019-01-25-kube-client-go-source-code-tracing.html
Kubernetes-context [org-0058]
- December 9, 2018
- Lîm Tsú-thuàn
- 2018-12-09-kubernetes-context.html
Kubernetes-context [org-0058]
- December 9, 2018
- Lîm Tsú-thuàn
- 2018-12-09-kubernetes-context.html
Fun-network-tcp-close [org-005A]
- November 30, 2018
- Lîm Tsú-thuàn
- 2018-11-30-fun-network-tcp-close.html
Fun-network-tcp-close [org-005A]
- November 30, 2018
- Lîm Tsú-thuàn
- 2018-11-30-fun-network-tcp-close.html
Xdp-some-note [org-0059]
- November 30, 2018
- Lîm Tsú-thuàn
- 2018-11-30-xdp-some-note.html
Xdp-some-note [org-0059]
- November 30, 2018
- Lîm Tsú-thuàn
- 2018-11-30-xdp-some-note.html
Kubernetes-start-from-pod [org-005C]
- October 27, 2018
- Lîm Tsú-thuàn
- 2018-10-27-kubernetes-start-from-pod.html
Kubernetes-start-from-pod [org-005C]
- October 27, 2018
- Lîm Tsú-thuàn
- 2018-10-27-kubernetes-start-from-pod.html
Test-llvm-go-binding-in-travis [org-005D]
- October 6, 2018
- Lîm Tsú-thuàn
- 2018-10-06-test-llvm-go-binding-in-travis.html
Test-llvm-go-binding-in-travis [org-005D]
- October 6, 2018
- Lîm Tsú-thuàn
- 2018-10-06-test-llvm-go-binding-in-travis.html
Httpexpect-go [org-005F]
- September 16, 2018
- Lîm Tsú-thuàn
- 2018-09-16-httpexpect-go.html
Httpexpect-go [org-005F]
- September 16, 2018
- Lîm Tsú-thuàn
- 2018-09-16-httpexpect-go.html
Practical-issue-about-dns-edns0 [org-005I]
- August 7, 2018
- Lîm Tsú-thuàn
- 2018-08-07-practical-issue-about-dns-edns0.html
Practical-issue-about-dns-edns0 [org-005I]
- August 7, 2018
- Lîm Tsú-thuàn
- 2018-08-07-practical-issue-about-dns-edns0.html
Reflection-in-go-create-a-stack-t [org-005J]
Reflection-in-go-create-a-stack-t [org-005J]
Magic-in-redux-go-2.1 [org-005K]
- July 4, 2018
- Lîm Tsú-thuàn
- 2018-07-04-magic-in-redux-go-2.1.html
Magic-in-redux-go-2.1 [org-005K]
- July 4, 2018
- Lîm Tsú-thuàn
- 2018-07-04-magic-in-redux-go-2.1.html
Error-is-value [org-005L]
- June 22, 2018
- Lîm Tsú-thuàn
- 2018-06-22-error-is-value.html
Error-is-value [org-005L]
- June 22, 2018
- Lîm Tsú-thuàn
- 2018-06-22-error-is-value.html
Design-of-redux-go-v2 [org-005N]
- May 17, 2018
- Lîm Tsú-thuàn
- 2018-05-17-design-of-redux-go-v2.html
Design-of-redux-go-v2 [org-005N]
- May 17, 2018
- Lîm Tsú-thuàn
- 2018-05-17-design-of-redux-go-v2.html
Cpp-thread-basic [org-0060]
- June 26, 2017
- Lîm Tsú-thuàn
- 2017-06-26-cpp-thread-basic.html
Cpp-thread-basic [org-0060]
- June 26, 2017
- Lîm Tsú-thuàn
- 2017-06-26-cpp-thread-basic.html
2. Notes [notes]
2. Notes [notes]
Axiom. Propositional extensionality [tt-0021]
- November 28, 2024
- Lîm Tsú-thuàn
Axiom. Propositional extensionality [tt-0021]
- November 28, 2024
- Lîm Tsú-thuàn
The propositional extensionality says that propositions that imply each other are equal
\[\text {propext} : \forall \ p\ q : \text {Prop}.\ (p \leftrightarrow q) \to p = q\]
Axiom. Proof irrelevance [tt-0020]
- November 27, 2024
- Lîm Tsú-thuàn
Axiom. Proof irrelevance [tt-0020]
- November 27, 2024
- Lîm Tsú-thuàn
The proof irrelevance is an axiom can be added into type theory to state that:
\[\frac { \Gamma \vdash p : \text {Prop} \quad \Gamma \vdash h : p \quad \Gamma \vdash h' : p }{ \Gamma \vdash h \equiv h' }\]so using which proofs is irrelevance.
Definition. Associated elements [math-00F0]
- November 20, 2024
- Lîm Tsú-thuàn
Definition. Associated elements [math-00F0]
- November 20, 2024
- Lîm Tsú-thuàn
Let \(D\) be an integral domain, \(a, b \in D\) are associated if \(a = ub\) where \(u\) is a unit of \(D\).
Definition. Irreducible [math-00F1]
- November 20, 2024
- Lîm Tsú-thuàn
Definition. Irreducible [math-00F1]
- November 20, 2024
- Lîm Tsú-thuàn
A nonzero element \(a\) of an integral domain \(D\) is called irreducible if \(a\) is not a unit and whenever \(b,c \in D\) with \(a = bc\), then \(b\) or \(c\) is a unit.
Definition. Primes [math-00F2]
- November 20, 2024
- Lîm Tsú-thuàn
Definition. Primes [math-00F2]
- November 20, 2024
- Lîm Tsú-thuàn
A nonzero element \(a\) of an integral domain \(D\) is called a prime if \(a\) is not a unit and
\[a \mid bc \implies a \mid b \text { or } a \mid c\]
Theorem. Primes => irreducibles [#291]
- November 20, 2024
- Lîm Tsú-thuàn
Theorem. Primes => irreducibles [#291]
- November 20, 2024
- Lîm Tsú-thuàn
In an integral domain, every prime is an irreducible.
The next theorem is why define PID.
Theorem. In PID, irreducibles = primes [#292]
- November 20, 2024
- Lîm Tsú-thuàn
Theorem. In PID, irreducibles = primes [#292]
- November 20, 2024
- Lîm Tsú-thuàn
In an principal integral domain, an element is an irreducible if and only if it is a prime.
Remark. The purpose of semantic theories [tt-001Y]
- November 15, 2024
- Lîm Tsú-thuàn
Remark. The purpose of semantic theories [tt-001Y]
- November 15, 2024
- Lîm Tsú-thuàn
- operational semantic: rules about how we compute
- denotational semantic: an object represents what we compute
Definition. Homogeneous polynomial [math-00EZ]
- November 11, 2024
- Lîm Tsú-thuàn
Definition. Homogeneous polynomial [math-00EZ]
- November 11, 2024
- Lîm Tsú-thuàn
A polynomial is homogeneous if whose nonzero terms all have the same degree.
Example. [#293]
- November 11, 2024
- Lîm Tsú-thuàn
Example. [#293]
- November 11, 2024
- Lîm Tsú-thuàn
Definition. Grothendieck topology [math-00EY]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Grothendieck topology [math-00EY]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Sieve [#294]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Sieve [#294]
- November 9, 2024
- Lîm Tsú-thuàn
A sieve on the object \(U\) is a family of morphisms \(R\) that saturated in the sense that, \((V \xrightarrow {\alpha } U) \in R\) implies \((W \xrightarrow {\alpha \circ \beta } U) \in R\) for any \(W \xrightarrow {\beta } V\).
Let \(C\) be a small category. A Grothendieck topology on \(C\) is defined by specifying, for each object \(U \in C\), a set \(J(U)\) of sieves on \(U\), called covering sieves of the topology, such that
- For any \(U\), the maximal sieve \(\{ \alpha \mid \fbox {?} \xrightarrow {\alpha } U \}\) is in \(J(U)\)
- If \(R \in J(U)\) and \(V \xrightarrow {f} U\) is a morphism of \(C\), then the sieve \[f^*(R) = \{ W \xrightarrow {\alpha } V \mid f\circ \alpha \in R \}\] is in \(J(V)\)
- If \(R \in J(U)\) and \(S\) is a sieve on \(U\) such that, for each \((V \xrightarrow {f} U) \in R\), we have \(f^*(S) \in J(V)\), then \(S \in J(U)\)
Remark. [#295]
- November 9, 2024
- Lîm Tsú-thuàn
Remark. [#295]
- November 9, 2024
- Lîm Tsú-thuàn
條件二使 Grothendieck pretopology 中的 with pullbacks 是不必要的。
Definition. Site [math-00EX]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Site [math-00EX]
- November 9, 2024
- Lîm Tsú-thuàn
Topos Theory
A site is a small category equipped with a Grothendieck topology (Definition [math-00EY]Definition [math-00EY]).
Definition. Grothendieck topology [math-00EY]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Grothendieck topology [math-00EY]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Sieve [#294]
- November 9, 2024
- Lîm Tsú-thuàn
Definition. Sieve [#294]
- November 9, 2024
- Lîm Tsú-thuàn
A sieve on the object \(U\) is a family of morphisms \(R\) that saturated in the sense that, \((V \xrightarrow {\alpha } U) \in R\) implies \((W \xrightarrow {\alpha \circ \beta } U) \in R\) for any \(W \xrightarrow {\beta } V\).
Let \(C\) be a small category. A Grothendieck topology on \(C\) is defined by specifying, for each object \(U \in C\), a set \(J(U)\) of sieves on \(U\), called covering sieves of the topology, such that
- For any \(U\), the maximal sieve \(\{ \alpha \mid \fbox {?} \xrightarrow {\alpha } U \}\) is in \(J(U)\)
- If \(R \in J(U)\) and \(V \xrightarrow {f} U\) is a morphism of \(C\), then the sieve \[f^*(R) = \{ W \xrightarrow {\alpha } V \mid f\circ \alpha \in R \}\] is in \(J(V)\)
- If \(R \in J(U)\) and \(S\) is a sieve on \(U\) such that, for each \((V \xrightarrow {f} U) \in R\), we have \(f^*(S) \in J(V)\), then \(S \in J(U)\)
Remark. [#295]
- November 9, 2024
- Lîm Tsú-thuàn
Remark. [#295]
- November 9, 2024
- Lîm Tsú-thuàn
條件二使 Grothendieck pretopology 中的 with pullbacks 是不必要的。
Definition. Grothendieck pretopology [math-00EW]
- November 6, 2024
- Lîm Tsú-thuàn
Definition. Grothendieck pretopology [math-00EW]
- November 6, 2024
- Lîm Tsú-thuàn
Topos Theory
Let \(C\) be a small category with pullbacks. A Grothendieck pretopology on \(C\) is defined by specifying, for each object \(U \in C\), a set \(P(U)\) of families of morphisms of the form
\[\{ U_i \xrightarrow {\alpha _i} U \mid i \in I \}\]called covering families of the pretopology, such that
- For any \(U\), singleton set of the identity morphism \(\{ U \xrightarrow {1} U \}\) is in \(P(U)\).
- If \(V \to U\) is a morphism in \(C\), and \(\{ U_i \to U \mid i \in I \}\) is in \(P(U)\), then the pullback \(\{ V \times _U U_i \xrightarrow {\pi _1} V \mid i \in I \}\) is in \(P(V)\).
- If \(\{ U_i \xrightarrow {\alpha _i} U \mid i \in I \}\), and \(\{ V_{ij} \xrightarrow {\beta _{ij}} U_i \mid j \in J_i \}\) in \(P(U_i)\) for each \(i \in I\), then \[\{ V_{ij} \xrightarrow {\alpha _i \circ \beta _{ij}} U \mid i \in I, j \in J_i \}\] is in \(P(U)\).
Definition. Second fundamental form [math-00EV]
- November 3, 2024
- Lîm Tsú-thuàn
Definition. Second fundamental form [math-00EV]
- November 3, 2024
- Lîm Tsú-thuàn
Let \(S\) be an oriented regular surface, and let \(p \in S\). Let \(\partial _1, \partial _2\) be an orthonormal basis of \(T_pS\) with respect to which the Weingarten map is represented by a diagonal matrix
\[\mathcal {W}_p = \begin {bmatrix}k_1 & 0 \\ 0 & k_2\end {bmatrix}\]then
- \(\pm \partial _1, \pm \partial _2\) are principal directions of \(S\) at \(p\).
- \(k_1, k_2\) are principal curvatures of \(S\) at \(p\).
- The second fundamental form of \(S\) at \(p\) \[II_p(v) = \langle \mathcal {W}_p(v), v \rangle = \langle -dN_p(v), v \rangle \] for all \(v \in T_pS\)
- If \(v \in T_pS\) with \(|v| = 1\), then \(II_p(v)\) is also called the normal curvature of \(S\) at \(p\) in the direction \(v\).
Remark. [#296]
- November 3, 2024
- Lîm Tsú-thuàn
Remark. [#296]
- November 3, 2024
- Lîm Tsú-thuàn
We now can also represent Gaussian curvature and mean curvature as
\[K(p) = k_1 k_2\]and
\[H(p) = \frac {1}{2}(k_1 + k_2)\]
Definition. Gaussian curvature and mean curvature [math-00ET]
- November 2, 2024
- Lîm Tsú-thuàn
Definition. Gaussian curvature and mean curvature [math-00ET]
- November 2, 2024
- Lîm Tsú-thuàn
This is a formal way of Gaussian curvature (高斯曲率直覺方式)
The determinant of Weingarten map
\[K(p) = \det {\mathcal {W}_p}\]is the Gaussian curvature of \(S\) at \(p\). The half of trace
\[H(p) = \frac {1}{2} \mathcal {W}_p \]is the mean curvature of \(S\) at \(p\).
Definition. Weingarten map (and Gauss map) [math-00EU]
- November 2, 2024
- Lîm Tsú-thuàn
Definition. Weingarten map (and Gauss map) [math-00EU]
- November 2, 2024
- Lîm Tsú-thuàn
Definition. Gauss map [#297]
- November 2, 2024
- Lîm Tsú-thuàn
Definition. Gauss map [#297]
- November 2, 2024
- Lîm Tsú-thuàn
Let \(S\) be an oriented surface, let \(N : S \to \R ^3\) be a unit normal vector field on \(S\). Thus, \(N(p)\) only outputs an element of the sphere \(S^2 \subset \R ^3\), so \(N\) is also a function \(S \to S^2\). Such \(N\) is called the Gauss map.
Differential of Gauss map [#298]
- November 2, 2024
- Lîm Tsú-thuàn
Differential of Gauss map [#298]
- November 2, 2024
- Lîm Tsú-thuàn
Consider \(N : S \to S^2\), its differential is \(dN_p : T_pS \to T_{N(p)} S^2\). However, we can see
\[T_pS = T_{N(p)} S^2\]Thus, we can see \(dN_p : T_pS \to T_pS\).
For every \(p \in S\), the linear transformation
\[\mathcal {W}_p = -dN_p : T_pS \to T_pS\]is called the Weingarten map.
Generalize Gauss map [#299]
- November 2, 2024
- Lîm Tsú-thuàn
Generalize Gauss map [#299]
- November 2, 2024
- Lîm Tsú-thuàn
The idea still work for higher dimension. Let \(S\) be an differentiable manifold with dimension \(n-1\), let \(N : S \to \R ^n\), then \(N : S \to S^{n-1} \subset \R ^n\).
Definition. Riemannian connection [math-00EP]
- October 31, 2024
- Lîm Tsú-thuàn
Definition. Riemannian connection [math-00EP]
- October 31, 2024
- Lîm Tsú-thuàn
Let \(M\) be a differentiable manifold with an affine connection \(\nabla \) and a Riemann metric \(\langle -,- \rangle \).
Compatible [#301]
- October 31, 2024
- Lîm Tsú-thuàn
Compatible [#301]
- October 31, 2024
- Lîm Tsú-thuàn
A connection is compatible with the metric \(\langle -,- \rangle \) if for any smooth curve \(\gamma \) and any pair of parallel vector fields \(P\) and \(P'\) along \(\gamma \), we have
\[\langle P,P' \rangle = \text {constant}\]
Theorem. Levi-Civita [math-00EQ]
- October 31, 2024
- Lîm Tsú-thuàn
Theorem. Levi-Civita [math-00EQ]
- October 31, 2024
- Lîm Tsú-thuàn
Riemannian Geometry §2
Given a Riemann manifold \(M\), there exists a unique affine connection \(\nabla \) on \(M\) satisfying the conditions
- \(\nabla \) is symmetric
- \(\nabla \) is compatible with the Riemann metric.
Proof. [#300]
- October 31, 2024
- Lîm Tsú-thuàn
Proof. [#300]
- October 31, 2024
- Lîm Tsú-thuàn
The \(\nabla \) will be determined by
\[\begin {aligned} \langle Z, \nabla _YX \rangle = &\frac {1}{2}(X\langle Y,Z \rangle + Y\langle Z,X \rangle - Z\langle X,Y \rangle \\ &- \langle [X,Z],Y \rangle - \langle [Y,Z],X \rangle - \langle [X,Y],Z \rangle ) \end {aligned}\]
Remark. [#302]
- October 31, 2024
- Lîm Tsú-thuàn
Remark. [#302]
- October 31, 2024
- Lîm Tsú-thuàn
A Riemannian (or Levi-Civita) connection on \(M\) is the unique connection from Levi-Civita theorem.
Definition. Christoffel symbol [math-00ES]
- October 31, 2024
- Lîm Tsú-thuàn
Definition. Christoffel symbol [math-00ES]
- October 31, 2024
- Lîm Tsú-thuàn
Let \((U,x)\) be a coordinate system. The functions \(\Gamma ^k_{ij}\) defined on \(U\) by
\[\nabla _{\partial _i}\partial _j = \Gamma ^k_{ij}\partial _k\]The coefficients of the connection \(\nabla \) on \(U\) or Christoffel symbols of the connection. From Theorem [math-00EQ]
\[\Gamma ^l_{ij} g_{lk} = \frac {1}{2}(\partial _i g_{jk} + \partial _j g_{ki} - \partial _k g_{ij})\]where \(g_{ij} = \langle \partial _i, \partial _j \rangle \). By inverse matrix \(g^{km}\), we got
\[\Gamma ^m_{ij} = \frac {1}{2} \sum _k (\partial _i g_{jk} + \partial _j g_{ki} - \partial _k g_{ij}) g^{km}\]In term of Christoffel symbols, the covariant derivative has the classical expression:
\[\frac {DV}{dt} = \sum _k ( \frac {d v^k}{d t} + \sum _{i,j} \Gamma ^k_{ij} v^j \frac {d x^i}{d t} ) \partial _k\]
Definition. Lie bracket (or Lie product) [math-00EL]
- October 30, 2024
- Lîm Tsú-thuàn
Definition. Lie bracket (or Lie product) [math-00EL]
- October 30, 2024
- Lîm Tsú-thuàn
Let \(X\) and \(Y\) be two \(C^\infty \) tangent vector fields on open set \(U\) of differentiable manifold \(M\), the Lie bracket is
\[[X,Y] := XY - YX\]which takes two tangent fields and produces a new tangent field. The Lie derivative
\[L_XY = [X,Y]\]
Theorem. The Lie bracket always another tangent vector space [#304]
- October 30, 2024
- Lîm Tsú-thuàn
Theorem. The Lie bracket always another tangent vector space [#304]
- October 30, 2024
- Lîm Tsú-thuàn
Generally \(XY\) is not a tangent vector space, by not having Leibniz property. However, \(XY - YX\) must be.
Proof. [#305]
- October 30, 2024
- Lîm Tsú-thuàn
Proof. [#305]
- October 30, 2024
- Lîm Tsú-thuàn
The boxed part is same at \(XY\) and \(YX\), and generally not \(0\), and \(XY - YX\) leave a part that satisfies Leibniz.
Remark. Geometry meaning [#306]
- October 30, 2024
- Lîm Tsú-thuàn
Remark. Geometry meaning [#306]
- October 30, 2024
- Lîm Tsú-thuàn
Lie bracket 的用途是,衡量
- 先沿著 \(X\) 方向走 \(t\) 再沿著 \(Y\) 走 \(s\)
- 先沿著 \(Y\) 方向走 \(s\) 再沿著 \(X\) 走 \(t\)
這兩種路徑的差距,一般來說都不是零。所以,下面的定理 Lie bracket 是核心關鍵
Theorem. Lie product is zero => vector fields produce a local coordinates [math-00EM]
- October 30, 2024
- Lîm Tsú-thuàn
Theorem. Lie product is zero => vector fields produce a local coordinates [math-00EM]
- October 30, 2024
- Lîm Tsú-thuàn
Let \(M\) be a \(n\)-dimensional \(C^\infty \)-manifold, \(q \in M\) and \(X_1, \dots , X_k\) be a list of linear independent \(C^\infty \)-vector fields, and \(1 \le k \le n\). Then if for all \(\alpha , \beta \)
\[[X_\alpha , X_\beta ] = 0\]There exists \(C^\infty \)-immersion locally, i.e.
\[\lambda : U \subseteq \R ^k \looparrowright M\]makes
- \(q \in \lambda (U)\) and
- \(X_\alpha = \frac {\partial \lambda }{\partial x^\alpha }\) for all \(\alpha \).
Proof. [#303]
- October 30, 2024
- Lîm Tsú-thuàn
Proof. [#303]
- October 30, 2024
- Lîm Tsú-thuàn
Let \(\varphi ^\alpha _t\) be the flow of \(X_\alpha \), i.e.
\[ \frac {d }{d t} \varphi ^\alpha _t(x) = X_\alpha \text { at } x \text {, for all } x \in M\]so defines
\[\lambda (x^1, x^2, \dots , x^k) = \varphi ^k_{x^k} \circ \cdots \circ \varphi ^1_{x^1}(q)\]- Apply \(\lambda \) to the origin point is \(q\), \(\lambda (0, \dots , 0) = q\)
- \[\begin {aligned} &\frac {\partial \lambda }{\partial x^\alpha }(x^1, \dots , x^k) \\ = &\frac {\partial }{\partial x^\alpha } \lambda (x^1, \dots , x^k) \\ = &\frac {\partial }{\partial x^\alpha } \varphi ^k_{x^k} \circ \cdots \circ \varphi ^1_{x^1}(q) \\ = &X_\alpha \vert _{\text {at } \lambda (x^1, \dots , x^k)} \end {aligned}\] so \(X_\alpha = \frac {\partial }{\partial x^\alpha }\)
Can see that \(\lambda \) is the target immersion.
Definition. Quotient group [math-00EJ]
- October 29, 2024
- Lîm Tsú-thuàn
Definition. Quotient group [math-00EJ]
- October 29, 2024
- Lîm Tsú-thuàn
Algebra: Chapter 0 §II.7
Let \(H\) be a normal subgroup of \(G\), the quotient group of \(G\) modulo \(H\) denoted \(G / H\), is the group \(G / \sim \) obtained from the relation \(\sim \) defined as
\[G / \sim \ = \{ aH \mid a \in G \} = \{ Ha \mid a \in G \}\]In terms of cosets, the product in \(G / H\) is defined by
\[(aH)(bH) = (ab)H\]The identity \(e_{G / H} = e_G H = H\).
Definition. Coset [math-00EK]
- October 29, 2024
- Lîm Tsú-thuàn
Definition. Coset [math-00EK]
- October 29, 2024
- Lîm Tsú-thuàn
The left-cosets of a subgroup \(H\) in a group \(G\) are the sets \(aH\) for all \(a \in G\). The right-cosets of \(H\) are the sets \(Ha\) for all \(a \in G\).
Notation. Left/right relations [#307]
- October 29, 2024
- Lîm Tsú-thuàn
Notation. Left/right relations [#307]
- October 29, 2024
- Lîm Tsú-thuàn
Definition. Kronecker delta [math-00EG]
- October 28, 2024
- Lîm Tsú-thuàn
Definition. Kronecker delta [math-00EG]
- October 28, 2024
- Lîm Tsú-thuàn
Kronecker delta \(\delta ^i_j\) is a two-index mathematical object such that
\[ \delta ^i_j = \begin {cases} 1 \text { if } i = j \\ 0 \text { if } i \ne j \end {cases} \]
Remark. [#310]
- October 28, 2024
- Lîm Tsú-thuàn
Remark. [#310]
- October 28, 2024
- Lîm Tsú-thuàn
If we are not considering a tensor, denotes \(\delta _{ij}\) is also existed.
Usage [#311]
- October 28, 2024
- Lîm Tsú-thuàn
Usage [#311]
- October 28, 2024
- Lîm Tsú-thuàn
Consider a vector represents via index notation \(A^i\), then
\[A^i = \delta ^i_j A^j\]
Solution. [#312]
- October 28, 2024
- Lîm Tsú-thuàn
Solution. [#312]
- October 28, 2024
- Lîm Tsú-thuàn
Consider \(\delta ^i_j\) as a finite matrix form, and \(i, j\) have the same dimension.
\[\begin {bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \\ 0 & 0 & 1 \end {bmatrix}\]Then \(A^i = \begin {bmatrix}a\\b\\c\end {bmatrix} = \delta ^i_j \begin {bmatrix}a\\b\\c\end {bmatrix} = \delta ^i_j A^j\). It's clear that this idea is general, even \(i, j\) have different dimensions, the form
\[\begin {bmatrix} 1 & 0 & 0 \\ 0 & 1 & 0 \end {bmatrix} \begin {bmatrix}a\\b\\c\end {bmatrix} = \begin {bmatrix}a\\b\end {bmatrix}\]
Notation. Index form and summation convention [math-00EH]
- October 28, 2024
- Lîm Tsú-thuàn
Notation. Index form and summation convention [math-00EH]
- October 28, 2024
- Lîm Tsú-thuàn
Instead of denotes a vector as \(\vec {A}\), index form denotes \(A^\mu \), \(\mu \) is not exponent here, but index to each component. Let's take a concrete example, if \(A^\mu \) has dimension \(4\), then \(\mu = 0, 1, 2, 3\), thus
\[ A^\mu = \begin {bmatrix}A^0 \\ A^1 \\ A^2 \\ A^3\end {bmatrix} \]An usual example is partial derivations as components (e.g. tangent space (切空間))
\[ \partial _\mu = \frac {\partial }{\partial x^\mu } = \begin {bmatrix}\partial _0\\\partial _1\\\partial _2\\\partial _3\end {bmatrix} = \begin {bmatrix}\frac {\partial }{\partial x^0}\\\frac {\partial }{\partial x^1}\\\frac {\partial }{\partial x^2}\\\frac {\partial }{\partial x^3}\end {bmatrix} \]
Summation convention [#309]
- October 28, 2024
- Lîm Tsú-thuàn
Summation convention [#309]
- October 28, 2024
- Lîm Tsú-thuàn
Let \(A_\mu \) and \(B^\mu \) both be dimension \(4\) vector, then
\[A_\mu B^\mu = \sum _{\mu =0}^3 A_\mu B^\mu = A_0B^0 + A_1B^1 + A_2B^2 + A_3B^3\]
Definition. Linear categories [math-00EE]
- October 28, 2024
- Lîm Tsú-thuàn
Definition. Linear categories [math-00EE]
- October 28, 2024
- Lîm Tsú-thuàn
A Gentle Introduction to Homological Mirror Symmetry, §1.4
Let \(\mathbb {k}\) be a fixed field. A category \(C\) is called a \(\mathbb {k}\)-linear category if all hom-spaces are \(\mathbb {k}\)-vector spaces and the multiplication is bilinear. An object \(X \in C\) is a zero object if for all \(Y \in C\), we have \(\text {Hom}_{C}(X, Y) = \text {Hom}_{C}(Y, X) = 0\).
A functor between two \(\mathbb {k}\)-linear categories is call \(k\)-linear if the maps between the hom-spaces are \(\mathbb {k}\)-linear.
Remark. [#652]
- October 28, 2024
- Lîm Tsú-thuàn
Remark. [#652]
- October 28, 2024
- Lîm Tsú-thuàn
Almost all natural functors between two \(\mathbb {k}\)-linear categories are \(\mathbb {k}\)-linear.
Example. [#653]
- October 28, 2024
- Lîm Tsú-thuàn
Example. [#653]
- October 28, 2024
- Lîm Tsú-thuàn
\(\text {VECT}(\mathbb {k})\), \(\text {vect}(\mathbb {k})\), \(\text {mat}(\mathbb {k})\) are examples of \(\mathbb {k}\)-linear categories. For any \(\mathbb {k}\)-algebra \(A\), we have \(\mathbb {k}\)-linear categories:
- MOD-\(A\) The category of all right \(A\)-modules
- Mod-\(A\) The category of all finitely generated right \(A\)-modules
- mod-\(A\) The category of all finitely-dimensional right \(A\)-modules
The zero object in these categories is zero vector space with trivial \(A\)-action. The hom-spaces in these categories are often denoted by \(\text {Hom}_{A}(M, N)\). Respectively, for left modules we have \(A\)-MOD, \(A\)-Mod, and \(A\)-mod.
Remark. [#654]
- October 28, 2024
- Lîm Tsú-thuàn
Remark. [#654]
- October 28, 2024
- Lîm Tsú-thuàn
Any \(\mathbb {k}\)-algebra \(A\) can also be considered as a \(\mathbb {k}\)-linear category \(A\) with one object.
Definition. Ring algebra [math-00ED]
- October 28, 2024
- Lîm Tsú-thuàn
Definition. Ring algebra [math-00ED]
- October 28, 2024
- Lîm Tsú-thuàn
Manifolds, Sheaves, and Cohomology, §14.2
A \(R\)-algebra \(C\) is a \(R\)-module \(C\) together with a bilinear map \(\cdot : C \times C \to C\), such that \((C, +, \cdot )\) is a ring.
Definition. Commutative algebra [#313]
- October 28, 2024
- Lîm Tsú-thuàn
Definition. Commutative algebra [#313]
- October 28, 2024
- Lîm Tsú-thuàn
A \(R\)-algebra is commutative if the ring is commutative.
Definition. (co) wedge and (co) end [math-00EC]
- October 26, 2024
- Lîm Tsú-thuàn
Definition. (co) wedge and (co) end [math-00EC]
- October 26, 2024
- Lîm Tsú-thuàn
Let \(P : \mathcal {C}^{op} \times \mathcal {C} \to \mathcal {D}\) be a functor
- a wedge is a dinatural transformation from constant \(\zeta : \Delta _D \multimap P\)
- dually, a cowedge is a dinatural transformation to constant \(\zeta : P \multimap \Delta _D\)
Definition. End [#314]
- October 26, 2024
- Lîm Tsú-thuàn
Definition. End [#314]
- October 26, 2024
- Lîm Tsú-thuàn
A end of \(P\) is an terminal wedge, which means: