f#隨著vsts 2010 beta1 發布也有一段時間了,園子裡應該也有不少人對它感興趣吧。下面的例子是我在學f# 基本語法時寫的乙個簡單sieve of eratosthenes 實現,通過剖析這一小段**,我希望大家能對f#有個簡單認識,並能自己寫一些簡單的小程式。
1let
getallprimesbefore n =
2let
container = array.create (n+1)
03letrec
loop acc =
function4|
->
list.rev acc5|
hd::tl
->6if
container.[hd] =
1then
7loop acc tl
8else
9for
j in
[hd .. hd .. n]
do10
container.[j]
<-111
loop (hd::acc) tl
12loop [
2.. n]
1314
letprimesbefore120 = getallprimesbefore
120廢話少說,直接進入正題吧
1let
getallprimesbefore n =
第一行,申明函式getallprimesbefore, 並且該函式有乙個引數n, 在這裡我沒有指定n的型別,因為編繹器可以通過函式體對n的型別進去推斷,比如在本例中,n就是int型別,當然我們也可以顯示的指定n的型別,比如 let getallprimesbefore (n:int),這樣我們就指定了n為int型 (注意:(n:int)中的括號不能省略,let getallprimesbefore n : int 的意思是該函式返回的值的int型)。說完了引數,再說下返回值,同樣,編繹器會根據函式體上下文對返回值型別進去推斷,所以我們不需要申明返回型別。
2let
container = array.create (n+1)
0第二行,首先請注意該行與第一行相對有乙個縮排(),f#和python一樣,也是通過縮進來組織**結構的。這一行我們定義了乙個變數container,它的型別是array,大小為 n+1, 並且值全部初使化為0
1let
recloop acc =
function2|
->
list.rev acc3|
hd::tl
->4if
container.[hd] =
1then
5loop acc tl
6else
7for
j in
[hd .. hd .. n] do8
container.[j]
<-19
loop (hd::acc) tl
接下來就是這個函式的主要部分了(原程式中的3-11行),首先我們定義了乙個遞迴函式(我們發現定義遞迴函式需要加rec關鍵字)。它接受兩個引數,acc和乙個list,有朋友可能要問了,這裡明明我只看到乙個引數acc,你說的那個list在哪呢?可能有細心的朋友也發現了這裡的函式定義不光前面有rec,在等號後面還加了個function,那麼function是做什麼用的呢?
letrec
loop acc =
function
這裡我需要首先講一下pattern matching, pattern matching有些類似於c#中的switch語句(當然它要比c#中的switch強大許多,但這不是本文的目地,所以略去不表),可以根據expr的值去執行某一具體分支,它的基本語法也很簡單,我們還是結合乙個具體例項來看一下(例子比較簡單,只是為了說明問題)。 這個例子大家很容易看懂吧,我就不詳細解釋了,只是說明一點,'_'用來匹配所有別的情況。
letshowgreeting laguageinuse =
match
laguageinuse
with|"
c#"->
printfn
"hello, c# developer!"|
"f#"->
printfn
"hello, f# developer!"|
_ ->
printfn
"hello, other developers!
"因為pattern matching在f#中的使用範圍實在太廣了,所以就引入了一種簡化版,這就是上面大家看到的等號後面的function的作用,我們可以把上面的例子簡化成
letshowgreeting =
function|"
c#"->
printfn
"hello, c# developer!"|
"f#"->
printfn
"hello, f# developer!"|
_ ->
printfn
"hello, other developers!
"怎麼樣?既少了給引數起名的煩惱,也少敲不少字吧,嘿嘿。
接下來我再簡單介紹下f#中非常重要的乙個基本型別list, 其基本表示形式為 [ item1;item2; .. ;itemn]
f#中list是immutable型別,我們只能訪問裡面的值,不能改動裡面的值,任何改動list的需求只能通過構建新的list來實現。稍一思考,大家就會很快發現要實現乙個高效的immutable list, 那最簡單的就是對其頭結點進去操作了(插入和刪除都可以達到o(1),當然插入和刪除會構建乙個新的list,原list不會改變),f#中的list也是基於這種形式,所有的list都可以看成是head+tail(除了head外的所有結點),f#提供了相應的庫函式list.hd, list.tl,並且提供了:: (cons operator)來幫助我們方便的構建乙個list,比如1::2::就表示list [1;2] (注意1和2之間我用的是;不是, 如果寫成[1,2],那個表示該list只有乙個元素 (1,2),至於(1,2)是什麼型別,為了使文章盡量緊湊,我們今天就不講了)
有了上面這些知識,再看本文一開始的函式就簡單多了
letrec
loop acc =
function|
->
list.rev acc
|hd::tl
->
ifcontainer.[hd] =
1then
loop acc tl
else
forj
in[hd .. hd .. n]
docontainer.[j]
<-
1loop (hd::acc) tl
首先,該函式的第二個引數是list,
當list為空時,就把acc反序返回,
當list不為空時,把list分成兩部分(hd::tl),檢查當當前值n (n的值等於td) 是否己被標記
如果己經被標記(container.[hd] =1),略過當前值,檢查接下來的值 loop acc tl
如果沒有被標記(當前值是素數),用當前值和acc構建乙個新list (hd::acc),並對當前值的所有倍數進去標記(for loop),然後檢查下乙個值 loop (hd::acc) tl
這裡有兩點需要特別說明一下:
1. container是乙個array型別的引數,array在f#中是mutable型別的容器,我們可以修改裡面的元素,訪問元素用array.[i], 修改元素用array.<-[i] = newvalue(不要忘記中間的.)
2. for loop的基本形式為 for in do, 我們可以使用[start .. end]或[start .. step .. end]來構建乙個range,當然,這裡的range其實也是乙個list
看完了內部函式,我們再接著往下看(原程式第12行)
loop [
2.. n]
這裡就很簡單了,呼叫我們剛剛定義的內部函式,(acc為空list , 第二個引數為list [2 .. n]),其返回值(list acc)就是函式getallprimesbefore的返回值,f#中函式有返回值時不需要敲return.
函式呼叫也很簡單,(不需要在引數與函式名之間加括號)
letprimesbefore100 = getallprimesbefore
100後記
1. f#中函式體內可以定義新的值,變數和函式。(只在當前函式體內可見)。當然,這樣做的好處顯而易見,我就不囉嗦了。
2. recursive function是functional programming中很常用的一種演算法實現方式。functional programming language往往會針對尾遞迴進行特別的優化,f#也不例外,所以我們需要盡可能的把遞迴寫成尾遞迴的形式,這個有時就需要像本文一樣借助accumulator來實現。
《結合例項學習f#》
1. 快速入門
2. 基本資料型別discriminated unions
F 入門學習(一)
開啟專案 6 3 6.0 3.0 6 3.0 會有波浪線,預能感知,藍色警告可以執行 字元型let x1 財 val x1 char 財 注釋let x1 財 一行注釋 哈哈 我是多行 注釋 串型別 f 是強型別語言 必須把型別分的清清楚楚的意思。val it string f 是強型別語言 用來幹...
Python學習(一) 快速入門
因為boss要求開始學習python,參考教材是 python核心程式設計 第二版 用的環境是ubuntu 15.04。程式輸出 使用print語句,這個和c的printf 類似。print語句缺省會給每一行新增乙個換行符,而只要在print語句最後新增乙個逗號,就可以使得輸出的元素排列在同一行。p...
CSS快速入門學習一
一 css語法 h1 color blue font size 12px h1就是html的標籤,又叫選被器,是被選擇樣式化的物件,color blue 就是效果一,font size 12px 效果二 二 來個例子 p 或者這樣,更方便讀取 p放到html裡的 就是 hello world thi...