2022年1月12日 星期三
如何做 Haskell 的 η conversion,以 (.).(.)為例
Haskell的函數直接支援 η(eta) conversion,也就是說函數的撰寫可以變成完全無參數。事實上還是會接收參數,只是經過 η conversion 之後可以不寫。於是就有像 (.).(.) 這種完全不知道在幹什麼的函數。這不是乳房的象形文字,是一個合法的函數,而且還很有用。當然最好別這樣寫,這樣寫沒人看得懂。(.).(.) 函數可以經由 η conversion 轉回來變成有參數,Haskell當中有一種機械化的代數運算方式計算出 (.).(.) 的型別,有了型別就知道它在幹什麼了。
2021年12月1日 星期三
國中生就會 y-combinator
國中的時候大家都做過一個題目:
$$\sqrt{2+\sqrt{2+\sqrt{2+\cdots}}}=?$$
這題目的做法是令$\sqrt{2+\sqrt{2+\sqrt{2+\cdots}}} = x$ ,接下來都會做了,兩邊都平方,就變成 $2+x=x^2$。其實也可以左邊加2再取根號,意思一樣。這裏當然有一個假設沒跟國中生講,就是$\sqrt{2+\sqrt{2+\sqrt{2+\cdots}}}$會收斂到一個數。
2017年7月27日 星期四
Haskell中用foldl實現foldr
假設折疊中的折疊函數是$f(x,y)$,要折疊$[1,2,3]$,初始值是$0$。
左折疊的精神如下:
$f(f(f(0 , 1) , 2) , 3)$
遞迴呼叫是發生在左邊的參數。
參數求值是從左到右的。因為一定要先遞迴到最深才能取得參數值,所以不能使用在無窮串列上。
左折疊的精神如下:
$f(f(f(0 , 1) , 2) , 3)$
遞迴呼叫是發生在左邊的參數。
參數求值是從左到右的。因為一定要先遞迴到最深才能取得參數值,所以不能使用在無窮串列上。
2017年7月24日 星期一
windows上的gvim如何設定預設字型
gvim上設定預設字型向來是一件麻煩事,尤其在windows上。
問題是參數不知道應該長怎樣,隨系統的不同而不同。
windows上,開啟gvim之前系統會執行"_vimrc"的內容。
首先用視窗界面("編輯"→"設定字型")來設定字型。
接下來利用":set guifont?"指令來觀察參數應該長怎樣。
然後在_vimrc中最後一行輸入 「 set guifont="剛剛看到的參數" 」就可以了。
我的gvim 8.0,windows 7,最後結果是這樣
set guifont=Source_Code_Pro_Medium:h12:cANSI:qDRAFT
問題是參數不知道應該長怎樣,隨系統的不同而不同。
windows上,開啟gvim之前系統會執行"_vimrc"的內容。
首先用視窗界面("編輯"→"設定字型")來設定字型。
接下來利用":set guifont?"指令來觀察參數應該長怎樣。
然後在_vimrc中最後一行輸入 「 set guifont="剛剛看到的參數" 」就可以了。
我的gvim 8.0,windows 7,最後結果是這樣
set guifont=Source_Code_Pro_Medium:h12:cANSI:qDRAFT
2011年12月20日 星期二
編輯程式常用gvim指令
自動完成:Ctrl + p 向上搜尋匹配並自動完成,Ctrl + n 向下
移動至匹配括號:%。跟v結合可以很快選擇依括號內區域
變更部份文字:c + 移動指令
搜尋:/pattern
取代::1,$s/s1/s2/g 將s1取代為s2
顯示(取消)行號: :set number (:set nonumber)
編譯目前的java檔案::!javac %
移動至匹配括號:%。跟v結合可以很快選擇依括號內區域
變更部份文字:c + 移動指令
搜尋:/pattern
取代::1,$s/s1/s2/g 將s1取代為s2
顯示(取消)行號: :set number (:set nonumber)
編譯目前的java檔案::!javac %
2011年11月9日 星期三
神奇的linux/unix運算程式dc
dc是一個linux/unix指令列工具,完全運用stack做運算
用它可能沒什麼特別的好處(除了可能會很快之外。照理說這種純stack運算的語言可以做到飛快),但是如果想對程式運作有更深的了解,花點時間玩一下會有幫助,因為所有程式的函數呼叫控制都是用stack完成。
寫了一個hanoi tower自娛用,執行dc -f hanoi.dc就可以了
hanoi.dc的內容如下:
用它可能沒什麼特別的好處(除了可能會很快之外。照理說這種純stack運算的語言可以做到飛快),但是如果想對程式運作有更深的了解,花點時間玩一下會有幫助,因為所有程式的函數呼叫控制都是用stack完成。
寫了一個hanoi tower自娛用,執行dc -f hanoi.dc就可以了
hanoi.dc的內容如下:
#function z : move source to destiny
[[ ]n ls n [ -> ] n ld n [ ]p]sz
#function Q : quit and clear top of stack n,s,d,i
[LnLsLdLi sbsbsbsb q]sQ
#function X(n,s,d,i) : hanoi tower function,
#n: number ; s: source ; d: destiny ; i: intermediate
[
ln 0=Q
ln 1- Sn
li ld Si Sd ls Ss
lXx
lzx
ln 1- Sn
li ls Si Ss ld Sd
lXx
LnLsLdLi sbsbsbsb #this line clears the top of parameter stacks
]SX
[number of disk:]P?
[start pillar:]P?
[destination pillar:]P?
[intermidiate pillar:]P?
SiSdSsSn
lXx
2011年9月22日 星期四
postgresql 中階層式資料表查詢
comment_id | parent_id | author | comment
------------+-----------+--------+---------------------------------
1 | 1 | Fran | What's the cause of this bug?
2 | 1 | Ollie | I think it's a null pointer
3 | 2 | Fran | No. I checked for that.
4 | 1 | Kukla | We need to check invalid input.
5 | 4 | Ollie | Yes, that's a bug.
6 | 4 | Fran | Yes, please add a check.
7 | 6 | Kukla | That fixed it.
以上列資料表為例(SQL Antipatterns, Bill Karwin, p36.),每一列都有一欄指向父親,最上層的父親欄位設為1(用null可以解決問題,但是很奇怪。因為null在sql中的邏輯意義是"未知",而不是"沒有",總之必須要有一個辦法表示root。設成1之後避免recursive query跑不完的辦法是把下面code當中的union all 改成union)。
如果資料庫有支援遞迴式查詢,用上述的結構實現階層式資料的話,也能用簡單的查詢查出資料。例如要查出4號comment為根的subtree,在postgresql只要運用以下查詢查詢即可
參考資料
------------+-----------+--------+---------------------------------
1 | 1 | Fran | What's the cause of this bug?
2 | 1 | Ollie | I think it's a null pointer
3 | 2 | Fran | No. I checked for that.
4 | 1 | Kukla | We need to check invalid input.
5 | 4 | Ollie | Yes, that's a bug.
6 | 4 | Fran | Yes, please add a check.
7 | 6 | Kukla | That fixed it.
以上列資料表為例(SQL Antipatterns, Bill Karwin, p36.),每一列都有一欄指向父親,最上層的父親欄位設為1(用null可以解決問題,但是很奇怪。因為null在sql中的邏輯意義是"未知",而不是"沒有",總之必須要有一個辦法表示root。設成1之後避免recursive query跑不完的辦法是把下面code當中的union all 改成union)。
如果資料庫有支援遞迴式查詢,用上述的結構實現階層式資料的話,也能用簡單的查詢查出資料。例如要查出4號comment為根的subtree,在postgresql只要運用以下查詢查詢即可
with RECURSIVE subtree_4(comment_id, parent_id) as (
select comment_id, parent_id from comments where comment_id = 4
union all
select c.comment_id, c.parent_id
from subtree_4 sub, comments c
where c.parent_id = sub.comment_id
)
select * from subtree_4;
2011年8月23日 星期二
樂透號碼產生器
所謂樂透號碼,就是從某範圍整數中,隨機且不重複的選取其中幾個。例如台灣的今彩就是從1到39當中選5個。要從電腦隨機產生一組號碼,比較基本的有以下兩種
1.每個號碼隨機選號,選重複的再去掉。但是這方法很笨,而且選號一多就會慢到不行。
2.模仿開彩方式,按照正確機率依序選擇號碼。以今彩為例,抽中39號的機率是5/39,下一步驟抽中38號的機率就變成5/38(上步驟未抽中39號)或4/38(上步驟抽中39號),依此類推。
第二個方式顯然快多了。下面awk程式(lottery.awk)實現此作法
在類似unix系統環境下,實行
echo "1 39 5" | awk -f lottery.awk
或是perl:
執行
$./lottery.pl 1 39 5
會印出1~39隨機取5個的數字
1.每個號碼隨機選號,選重複的再去掉。但是這方法很笨,而且選號一多就會慢到不行。
2.模仿開彩方式,按照正確機率依序選擇號碼。以今彩為例,抽中39號的機率是5/39,下一步驟抽中38號的機率就變成5/38(上步驟未抽中39號)或4/38(上步驟抽中39號),依此類推。
第二個方式顯然快多了。下面awk程式(lottery.awk)實現此作法
在類似unix系統環境下,實行
echo "1 39 5" | awk -f lottery.awk
或是perl:
#!/usr/bin/perl
$min=$ARGV[0];
$max=$ARGV[1];
$needed=$ARGV[2];
$available=$max-$min+1;
while (@selected < $ARGV[2]) {
if(rand() < $needed/$available) {
push(@selected, $available);
$needed -= 1;
}
$available -= 1;
}
foreach $number (@selected) {
print($number . "\n");
}
執行
$./lottery.pl 1 39 5
會印出1~39隨機取5個的數字
2011年8月16日 星期二
程式研究:akka的remote actor
akka的remote actor 是個神奇的東西,自動幫你處理了傳輸格式,你只要關心scala當中跟actor互傳的信息就好了。不過要讓akka 首頁上那段非常簡短的程式碼跑起來,需要不少準備。
首先是sbt,這是scala用的build tool,設定檔完全用scala語法表達,簡單方便。
執行sbt只需要一個jar檔和一個script,windows是bat檔,linux是shell script,設好了之後任意目錄下
執行sbt,回答問題之後就會自動產生目錄架構,之後就可以開始寫設定檔和程式了。
設定檔都在project目錄下,源代碼在src目錄下
project/build 之下,建立一個Project.scala,內容如下:
project/plugins 之下,建立一個Plugins.scala,內容如下
之後在sbt下,執行reload和update,就會按照上述的設定抓好必要的檔案並決定從屬關係
之後執行console,可以在此環境下直接執行scala的類似直譯器。
打開第二個command prompt視窗,在工作目錄下再運行一個sbt,此視窗當作client用,第一個視窗當作server,兩個視窗都執行console
server視窗輸入
client視窗輸入
這樣就收到了server傳來的訊息了。把server當成一個actor用 akka 1.1.3的文件
首先是sbt,這是scala用的build tool,設定檔完全用scala語法表達,簡單方便。
執行sbt只需要一個jar檔和一個script,windows是bat檔,linux是shell script,設好了之後任意目錄下
執行sbt,回答問題之後就會自動產生目錄架構,之後就可以開始寫設定檔和程式了。
設定檔都在project目錄下,源代碼在src目錄下
project/build 之下,建立一個Project.scala,內容如下:
import sbt._
class ChatProject(info: ProjectInfo) extends DefaultProject(info) with AkkaProject {
val akkaRepo = "Akka Repo" at "http://akka.io/repository"
val akkaSTM = akkaModule("stm")
val akkaRemote = akkaModule("remote")
}
project/plugins 之下,建立一個Plugins.scala,內容如下
import sbt._
class Plugins(info: ProjectInfo) extends PluginDefinition(info) {
val akkaRepo = "Akka Repo" at "http://akka.io/repository"
val akkaPlugin = "se.scalablesolutions.akka" % "akka-sbt-plugin" % "1.1.3"
}
之後在sbt下,執行reload和update,就會按照上述的設定抓好必要的檔案並決定從屬關係
之後執行console,可以在此環境下直接執行scala的類似直譯器。
打開第二個command prompt視窗,在工作目錄下再運行一個sbt,此視窗當作client用,第一個視窗當作server,兩個視窗都執行console
server視窗輸入
import akka.actor.Actor
import Actor._
class HelloActor extends Actor {
def receive = {
case "Hello" => self.reply("world")
}
}
remote.start("localhost", 9999)
remote.register("hello-service",actorOf[HelloActor])
client視窗輸入
import akka.actor.Actor
import Actor._
val actor = remote.actorFor("hello-service", "localhost", 9999)
val result = actor !! "Hello"
這樣就收到了server傳來的訊息了。把server當成一個actor用 akka 1.1.3的文件
2011年8月2日 星期二
程式語言研究:scala 1.9
半年前發覺一個有趣的語言scala,它企圖結合編譯式和直譯式語言,以及物件導向和函數導向語言的優點,形成一套有趣卻眉角很多的程式語言,不管怎樣比java好很多是真的,但是發覺缺點主要有兩個,第一是型別參數,因為型別可以不固定,但是卻必須遵從某種形式,第二是仍然擺脫不了java,光靠scala自己仍是不足,經常必須要去用到java的物件或函數。換句話說就是只學了scala仍然不夠,還是得學java,變成想要用scala的話得學兩種語言,相當麻煩。
1.9版新增功能中最有趣的還是maxBy, minBy, permutations 和 combinations這幾個在collection中的方法,後面兩個組合學的函數還是遵從辭典式排列的,不過一般這種函數輸出都會照辭典式排列就是。
scala自帶的actor其實還不夠好用,配合akka服用會愉快許多。
1.9版新增功能中最有趣的還是maxBy, minBy, permutations 和 combinations這幾個在collection中的方法,後面兩個組合學的函數還是遵從辭典式排列的,不過一般這種函數輸出都會照辭典式排列就是。
scala自帶的actor其實還不夠好用,配合akka服用會愉快許多。
2010年8月26日 星期四
Mathematica研究:常用的數字字串函數
Characters[#1] 把#1變成一個字元List。
例如Characters["abcd"]結果是{"a","b","c","d"}
Partition[#1,#2] 把#1這個List內部分割成幾個等長,長度為#2的List
FromCharacterCode[#1] 把數字#1當成ascii code轉成字元
FromDigits[#1,#2] 把#1這個數位List轉成以#2為base的數字
例如FromDigits[{1,0,1},2]結果是5
FactorInteger[#1] 把#1表示成#1的質因數乘積
例如Characters["abcd"]結果是{"a","b","c","d"}
Partition[#1,#2] 把#1這個List內部分割成幾個等長,長度為#2的List
FromCharacterCode[#1] 把數字#1當成ascii code轉成字元
FromDigits[#1,#2] 把#1這個數位List轉成以#2為base的數字
例如FromDigits[{1,0,1},2]結果是5
FactorInteger[#1] 把#1表示成#1的質因數乘積
訂閱:
文章 (Atom)