<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    莊周夢(mèng)蝶

    生活、程序、未來(lái)
       :: 首頁(yè) ::  ::  :: 聚合  :: 管理

        今天費(fèi)了一個(gè)下午安裝了redhat9,并且安裝了需要使用的jdk5、netbean、ruby和Erlang。做個(gè)備忘。

    一。安裝jdk5
    1.到sun的網(wǎng)站上下載jdk5與netbean5.5的捆綁版本,注意要linux平臺(tái)的

    2.比如下載到/root/目錄下,執(zhí)行
    chmod 755 jdk-1_5_0_12-nb-5_5_1-linux-ml.bin
    然后執(zhí)行:
    ./jdk-1_5_0_12-nb-5_5_1-linux-ml.bin
    就會(huì)自動(dòng)啟動(dòng)安裝向?qū)В宦愤x擇確定下去就OK了。

    3.設(shè)置環(huán)境變量,這時(shí)其實(shí)沒(méi)有設(shè)置就可以啟動(dòng)netbean了,不過(guò)為了在終端執(zhí)行,還是要設(shè)置下環(huán)境變量,使用vi編輯/etc/profile配置文件,在最后面加上:
    JAVA_HOME=/opt/jdk1.5.0_12
    PATH
    =/opt/jdk1.5.0_12/bin:$PATH
    CLASSPATH
    =/opt/jdk1.5.0_12/lib/dt.jar:/opt/jdk1.5.0_12/lib/tools.jar
    export JAVA_HOME PATH CLASSPATH
    保存退出,reboot下就OK

    二。安裝ruby
    1.到ruby-lang.org下載ruby-1.8.6.tar.gz
    2.解壓縮并進(jìn)入解壓后的目錄:
    tar xzvf ruby-1.8.6.tar.gz
    cd ruby-1.8.6

    3.默認(rèn)是安裝/usr/local目錄下,可以通過(guò)下面的命令設(shè)置安裝到/usr/local/ruby目錄下:
    /.configure -prefix=/usr/local/ruby

    4.執(zhí)行命令:make && make install

    5.再次編輯vi /etc/profile,修改我們?cè)谏厦嫣岬降腜ATH,把ruby的bin加進(jìn)去:
    PATH=/usr/local/ruby/bin:/opt/jdk1.5.0_12/bin:$PATH

    6.測(cè)試下是否正確安裝,
    ruby -version
    ruby -e "puts 'hello'"

    三、Erlang的安裝

    1.到Erlang.org下載最新版本的linux平臺(tái)下的Erlang(源代碼版本,需要自己編譯),比如otp_src_R11B-5.tar.gz

    2.解壓縮,并進(jìn)入解壓后的目錄:
    tar zxvf otp_src_R11B-5.tar.gz
    cd otp_src_R11B-5

    3.build Erlang需要下列工具,確認(rèn)你的linux版本有安裝:
     GNU make

     GNU C compiler

     Perl 5

     OpenSSL

     Sun Java jdk-1.2.2

     X Windows

     sed  solaris平臺(tái)需要

     Flex 可選

    4.安裝過(guò)程,順序執(zhí)行下列命令,包括OTP在內(nèi)都將被安裝
    1)export LANG=#如果是C Shell,執(zhí)行setenv LANG C,linux一般是Bourne shell



    2)./configure

    3)make

    4)make install

    5.確認(rèn)安裝正確,新開(kāi)一個(gè)終端,執(zhí)行erl進(jìn)入Erlang shell

    最后啟動(dòng)下ssh,允許防火墻通過(guò)ssh執(zhí)行下面的命令,在windows上搞個(gè)putty
    iptables -A INPUT -p tcp --sport 22 -j ACCEPT
    iptables -A OUTPUT -p tcp --dport 22 -j ACCEPT




    posted @ 2007-06-28 18:08 dennis 閱讀(1006) | 評(píng)論 (0)編輯 收藏

    這一節(jié)的內(nèi)容非常有趣,通過(guò)將序列作為interface,在此基礎(chǔ)上進(jìn)而提取出各種高階操作(map,filter,accumulate,enumerate等),由此引出模塊化設(shè)計(jì)的討論。模塊化設(shè)計(jì)帶來(lái)復(fù)雜性的降低,同時(shí)可能引入性能上的損失,比如書(shū)中對(duì)sum-odd-squares過(guò)程的兩種寫(xiě)法,原來(lái)的寫(xiě)法枚舉列表元素的過(guò)程散落在累積、過(guò)濾、映射的過(guò)程中,主要一次循環(huán)就夠了,而通過(guò)三個(gè)高階過(guò)程來(lái)操作反而需要3次的遍歷。

    習(xí)題2.33,將map,append,length基本過(guò)程用累積操作重新定義,聯(lián)系以往的實(shí)現(xiàn)通過(guò)觀察和測(cè)試可以得出:
    (define (map p sequence)
      (accumulate  (
    lambda(x y) 
                    (cons (p x) y))       
                           () sequence))
    (define (append seq1 seq2)
      (accumulate cons seq2 seq1))
    (define (length sequence)
      (accumulate (
    lambda(x y)
                    (
    + 1 y))
                    0 sequence))
    難點(diǎn)就在于累積的操作。

    習(xí)題2.34,Horner規(guī)則求多項(xiàng)式,難點(diǎn)也是累積操作的定義:
    (define (horner-eval x coefficient-sequence)
      (accumulate (
    lambda(this-coeff higher-terms)
                    (
    + this-coeff (* x higher-terms)))
                  0 coefficient
    -sequence))
    只要記住lambda中的y其實(shí)是另一個(gè)遞歸的accumulate就比較容易完成了。
    測(cè)試下:
    > (horner-eval 2 (list 1 3 0 5 0 1))
     
    79

    習(xí)題2.35,利用map和accumulate重新定義count-leaves統(tǒng)計(jì)樹(shù)的節(jié)點(diǎn)數(shù)目:
    (define (count-leaves t)
      (accumulate 
    + 0 (map (lambda (x) (if (pair? x) (count-leaves x) 1)) t)))
    map過(guò)程的參數(shù)op是過(guò)程
    (lambda (x) (if (pair? x) (count-leaves x) 1))
    當(dāng)x是列表,遞歸調(diào)用count-leaves,否則返回個(gè)數(shù)1

    習(xí)題2.36,列表的列表,因此map過(guò)程的第一個(gè)參數(shù)是一個(gè)過(guò)程作用于列表中的每個(gè)列表,當(dāng)然是采用car將它們首項(xiàng)取出然后進(jìn)行op操作,因此:
    (define (accumulate-n op init seqs)
      (
    if (null? (car seqs))
          ()
          (cons (accumulate op init (map car seqs))
                (accumulate
    -n op init (map cdr seqs)))))

    習(xí)題2.37,list作為L(zhǎng)isp的基本結(jié)構(gòu)可以演化出各式各樣的復(fù)雜結(jié)構(gòu),比如此題就將列表作為矢量,矢量通過(guò)組合成為矩陣,3個(gè)解答就是矩陣的運(yùn)算:
    (define (dot-product v w)
      (accumulate 
    + 0 (map * v w)))
    (define (matrix
    -*-vector m v)
      (map (
    lambda (x) (dot-product x v)) m))
    (define (transpose mat)
      (accumulate
    -n cons () mat))
    (define (matrix
    -*-matrix m n)
      (let ((cols (transpose n)))
        (map (
    lambda (x) (matrix-*-vector cols x)) m)))
    知道矩陣運(yùn)算的定義得出結(jié)果并不困難。

    習(xí)題2.38,計(jì)算下結(jié)果:
    > (fold-right / 1 (list 1 2 3))
    1 1/2
    ;也就是3
    /2

    > (fold-left / 1 (list 1 2 3))
    1/6
    > (fold-right list () (list 1 2 3))
    (
    1 (2 (3 ())))
    > (fold-left list () (list 1 2 3))
    (((() 
    123)

    如果想使這兩個(gè)過(guò)程的結(jié)果相同,op需要滿足交換率和結(jié)合率的條件。

    習(xí)題2.39:
    ;2.39
    (define (reverse
    -list sequence)
      (fold
    -right (lambda(x y)(append y (list x))) () sequence))
    (define (reverse
    -list2 sequence)
      (fold
    -left (lambda(x y) (cons y x)) () sequence))




    posted @ 2007-06-27 15:14 dennis 閱讀(488) | 評(píng)論 (3)編輯 收藏

        這個(gè)類在spring2.01前沒(méi)有被改寫(xiě),spring2.06似乎已經(jīng)改寫(xiě)了,還未看源碼。不過(guò)這不是我所在意的問(wèn)題。我在《org.springframework.beans簡(jiǎn)單解讀》中的對(duì)這個(gè)類的理解是不正確的。我們先看看Guillaume Poirier對(duì)這個(gè)類中為什么使用WeakHashMap的解釋:

    WeakHashMap is implemented with WeakReference for keys, and strong reference for values. That means if the value has a strong reference on the key, then the key cannot be garbage collected until the WeakHashMap is ready for collection. However, if the value has no strong reference on its key, then being in the WeakHashMap won't prevent the key and value from being garbage collected if it is otherwise ready. The WeakHashMap knows when to remove the key (and the value with it) by using the notification provided by the java.lang.ref package. For more information on this, see: http://java.sun.com/j2se/1.4.2/docs/api/java/lang/ref/package-summary.html

    So the problem here with the CachedIntrospectionResults is that it uses BeanInfo and PropertyDescriptor that both have strong reference to the class (indirectly by a reference on Methods of the class). That will be solved with JDK 1.5 that uses a combinaison of Weak and Soft Reference to the Class and Method objects, but for 1.4.2, there's not really any better solution than to flush the Introspector's cache and/or use WeakReference on CachedIntrospectionResults. Using WeakReference on the CachedIntrospectionResults is safer, but decrease performance, and in such case a manual Instrospector.flushFromCaches(Class) must be used, so that the Instrospector does not keep a strong reference on the BeanInfo.

    When a webapp is hot-redeployed, a new ClassLoader is created to load the webapp, and the old one is thrown away, expected to be garbage collected. For the collection to happen, the server must clear any strong reference to the ClassLoader or its classes, and also the webapp must make sure that any code in parent ClassLoaders (or siblings) clear any reference it might have to any of the webapp's class.

        照他的說(shuō)法和參考《深入JVM》一書(shū),對(duì)Class有強(qiáng)引用的有:ClassLoader,java.beans.BeanInfo,java.beans.PropertyDescriptor,java.lang.reflect.Method。因?yàn)樵谶@個(gè)緩存中使用Class作為key,而Value是CachedIntrospectionResults,CachedIntrospectionResults中持有BeanInfo和Method的引用,這兩個(gè)都對(duì)Class對(duì)象有強(qiáng)引用(這一點(diǎn)據(jù)說(shuō)在jdk5中已經(jīng)修改,被改成軟引用和弱引用的組合,而在jdk1.4.2需要這樣的處理),導(dǎo)致在web應(yīng)用關(guān)閉或者熱部署的時(shí)候,舊的ClassLoader和它引用的類不能被回收,因此使用弱引用包裝CachedIntrospectionResults對(duì)象作為Value。web應(yīng)用關(guān)閉或者熱部署的時(shí)候,會(huì)new新的ClassLoader用于裝載類,這就是CachedIntrospectionResults判斷緩存是否safe的根據(jù)所在,判斷要緩存的Class引用的ClassLoader是否相同。
        當(dāng)使用JavaBean的內(nèi)省時(shí),使用Introspector,jdk會(huì)自動(dòng)緩存內(nèi)省的信息(BeanInfo),這一點(diǎn)可以理解,因?yàn)閮?nèi)省通過(guò)反射的代價(jià)是高昂的。當(dāng)ClassLoader關(guān)閉的時(shí)候,Introspector的緩存持有BeanInfo的信息,而B(niǎo)eanInfo持有Class的強(qiáng)引用,這將導(dǎo)致ClassLoader和它引用的Class等對(duì)象不能被垃圾收集器回收,因此在關(guān)閉前,需要手工清除Introspector中的緩存,調(diào)用Introspector.flushFromCaches,這就是CachedIntrospectionResults中當(dāng)?shù)玫紹eanInfo后為什么要執(zhí)行下面這段代碼的原因:
                this.beanInfo = Introspector.getBeanInfo(clazz);

                
    // Immediately remove class from Introspector cache, to allow for proper
                
    // garbage collection on class loader shutdown - we cache it here anyway,
                
    // in a GC-friendly manner. In contrast to CachedIntrospectionResults,
                
    // Introspector does not use WeakReferences as values of its WeakHashMap!
                Class classToFlush = clazz;
                
    do {
                    Introspector.flushFromCaches(classToFlush);
                    classToFlush 
    = classToFlush.getSuperclass();
                }
                
    while (classToFlush != null);

    說(shuō)到這里,spring中有一個(gè)比較少人注意的Listener——org.springframework.web.util.IntrospectorCleanupListener,這個(gè)類的說(shuō)明如下:

    它是一個(gè)在web應(yīng)用關(guān)閉的時(shí)候,清除JavaBeans Introspector緩存的監(jiān)聽(tīng)器.在web.xml中注冊(cè)這個(gè)listener.可以保證在web 應(yīng)用關(guān)閉的時(shí)候釋放與掉這個(gè)web 應(yīng)用相關(guān)的class loader 和由它加載的類
     
    如果你使用了JavaBeans Introspector來(lái)分析應(yīng)用中的類,系統(tǒng)級(jí)Introspector 緩沖中會(huì)保留這些類的hard引用。結(jié)果在你的web應(yīng)用關(guān)閉的時(shí)候,這些類以及web 應(yīng)用相關(guān)的class loader沒(méi)有被垃圾收集器回收.
     
    不幸的是,清除Introspector的唯一方式是刷新整個(gè)緩存。這是因?yàn)槲覀儧](méi)法判斷哪些是屬于你的應(yīng)用的引用.所以刪除被緩沖的introspection會(huì)導(dǎo)致把這臺(tái)server上的所有應(yīng)用的introspection(內(nèi)省)結(jié)果都刪掉.
     
    需要注意的是,spring容器托管的bean不需要使用這個(gè)監(jiān)聽(tīng)器.因?yàn)閟pring它自己的introspection所使用的緩沖在分析完一個(gè)類之后會(huì)被馬上從javaBeans Introspector緩沖中清除掉(上面提到的代碼說(shuō)明了這一點(diǎn))

    一般的應(yīng)用基本不會(huì)直接用到JavaBean的內(nèi)省方法,所以一般不用考慮遇到此類內(nèi)省資源泄露,但是,很多的類庫(kù)或者框架(比如struts,Quartz)沒(méi)有清除Introspector。這個(gè)Listener就是為它們“擦屁股”的。請(qǐng)注意,這個(gè)監(jiān)聽(tīng)器需要注冊(cè)在web.xml中的所有應(yīng)用監(jiān)聽(tīng)器之前(比如ContentLoaderListener之前)
    <listener>
       
    <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>
    </listener>

        參考資料:
     《深入Java虛擬機(jī)》
     《Class對(duì)象什么時(shí)候被回收?
     《Spring API Doc
      《ss目前的設(shè)計(jì)有引起內(nèi)存泄露而導(dǎo)致down機(jī)的隱患
     以及一篇非常好的解釋java引用類的文章《Java對(duì)象的強(qiáng)、軟、弱和虛引用




    posted @ 2007-06-26 10:39 dennis 閱讀(3007) | 評(píng)論 (1)編輯 收藏

         摘要:     去了趟福州,事情沒(méi)搞定,托給同學(xué)幫忙處理了,回家休息了兩天就來(lái)上班了。回家這幾天最大的收獲是第四次重讀《深入Java虛擬機(jī)》,以前不大明了的章節(jié)豁然開(kāi)朗,有種開(kāi)竅的感覺(jué),水到渠成,看來(lái)技術(shù)的學(xué)習(xí)還是急不來(lái)。    閑話不提,繼續(xù)Erlang的學(xué)習(xí),上次學(xué)習(xí)到分布式編程的章節(jié),剩下三章分別是錯(cuò)誤處理、構(gòu)造健壯的系統(tǒng)和雜項(xiàng),錯(cuò)誤處理和...  閱讀全文

    posted @ 2007-06-25 17:10 dennis 閱讀(6107) | 評(píng)論 (0)編輯 收藏

        明天要回家一個(gè)星期了,好好休息下。今天找到別人翻譯的Erlang編程手冊(cè),值的好好讀一遍。
        所謂分布式的Erlang應(yīng)用是運(yùn)行在一系列Erlang節(jié)點(diǎn)組成的網(wǎng)絡(luò)之上。這樣的系統(tǒng)的性質(zhì)與單一節(jié)點(diǎn)上的Erlang系統(tǒng)并沒(méi)有什么不同。分布式這是個(gè)“大詞”,Erlang從語(yǔ)言原生角度支持分布式編程,相比于java簡(jiǎn)單不少。
    一、分布式機(jī)制
    下列的BIFs是用于分布式編程:
    spawn(Node, Mod, Func, Args)
    啟動(dòng)遠(yuǎn)程節(jié)點(diǎn)的一個(gè)進(jìn)程

    spawn_link(Node, Mod, Func, Args)
    啟動(dòng)遠(yuǎn)程節(jié)點(diǎn)的一個(gè)進(jìn)程并創(chuàng)建連接到該進(jìn)程

    monitor_node(Node, Flag)
    如果Flag是true,這個(gè)函數(shù)將使調(diào)用(該函數(shù))的進(jìn)程可以監(jiān)控節(jié)點(diǎn)Node。如果節(jié)點(diǎn)已經(jīng)舍棄或者并不存在,調(diào)用的進(jìn)程將收到一個(gè){nodedown,Node}的消息。如果Flag是false,監(jiān)控將被關(guān)閉

    node()
    返回我們自己的進(jìn)程name

    nodes()
    返回其他已知的節(jié)點(diǎn)name列表

    node(Item)
    返回原來(lái)Item的節(jié)點(diǎn)名稱,Item可以是Pid,引用(reference)或者端口(port)

    disconnect_node(Nodename)
    從節(jié)點(diǎn)Nodename斷開(kāi)。

        節(jié)點(diǎn)是分布式Erlang的核心概念。在一個(gè)分布式Erlang應(yīng)用中,術(shù)語(yǔ)(term)節(jié)點(diǎn)(node)意味著一個(gè)可以加入分布式transactions的運(yùn)行系統(tǒng)。通過(guò)一個(gè)稱為net kernal的特殊進(jìn)程,一個(gè)獨(dú)立的Erlang系統(tǒng)可以成為一個(gè)分布式Erlang系統(tǒng)的一部分。當(dāng)net kernal進(jìn)程啟動(dòng)的時(shí)候,我們稱系統(tǒng)是alive的。

        與遠(yuǎn)程節(jié)點(diǎn)上的進(jìn)程進(jìn)行通信,與同一節(jié)點(diǎn)內(nèi)的進(jìn)程通信只有一點(diǎn)不同:
      
       {Name, Node} ! Mess.
    顯然,需要接收方增加一個(gè)參數(shù)Node用于指定接受進(jìn)程所在的節(jié)點(diǎn)。節(jié)點(diǎn)的name一般是用@隔開(kāi)的atom類型,比如pong@dennis,表示計(jì)算機(jī)名為dennis上的pong節(jié)點(diǎn)。通過(guò)執(zhí)行:
    erl -sname pong
    將在執(zhí)行的計(jì)算機(jī)中創(chuàng)建一個(gè)節(jié)點(diǎn)pong。為了運(yùn)行下面的例子,你可能需要兩臺(tái)計(jì)算機(jī),如果只有一臺(tái),只要同時(shí)開(kāi)兩個(gè)Erlang系統(tǒng)并以不同的節(jié)點(diǎn)名稱運(yùn)行也可以。

    二、一些例子。
        這個(gè)例子完全來(lái)自上面提到的翻譯的連接,關(guān)于分布式編程的章節(jié)。我增加了截圖和說(shuō)明。
    首先是代碼:
    -module(tut17).

    -export([start_ping/1, start_pong/0,  ping/2, pong/0]).

    ping(
    0, Pong_Node) ->
        {pong
    , Pong_Node} ! finished,
        io
    :format("ping finished~n", []);

    ping(N
    , Pong_Node) ->
        {pong
    , Pong_Node} ! {ping, self()},
        receive
            pong 
    ->
                io
    :format("Ping received pong~n", [])
        end
    ,
        ping(N 
    - 1, Pong_Node).

    pong() 
    ->
        receive
            finished 
    ->
                io
    :format("Pong finished~n", []);
            {ping
    , Ping_PID} ->
                io
    :format("Pong received ping~n", []),
                Ping_PID 
    ! pong,
                pong()
        end
    .

    start_pong() 
    ->
        register(pong
    , spawn(tut17, pong, [])).

    start_ping(Pong_Node) 
    ->
        spawn(tut17
    , ping, [3, Pong_Node]).

        代碼是創(chuàng)建兩個(gè)相互通信的進(jìn)程,相互發(fā)送消息并通過(guò)io顯示在屏幕上,本來(lái)是一個(gè)單一系統(tǒng)的例子,現(xiàn)在我們讓兩個(gè)進(jìn)程運(yùn)行在不同的兩個(gè)節(jié)點(diǎn)上。注意start_ping方法,創(chuàng)建的進(jìn)程調(diào)用ping方法,ping方法有兩個(gè)參數(shù),一個(gè)是發(fā)送消息的次數(shù),一個(gè)就是遠(yuǎn)程節(jié)點(diǎn)的name了,也就是我們將要?jiǎng)?chuàng)建的進(jìn)程pong的所在節(jié)點(diǎn)。start_pong創(chuàng)建一個(gè)調(diào)用函數(shù)pong的進(jìn)程,并注冊(cè)為名字pong(因此在ping方法中可以直接發(fā)送消息給pong)。
        我是在windows機(jī)器上測(cè)試,首先打開(kāi)兩個(gè)cmd窗口,并cd到Erlang的安裝目錄下的bin目錄,比如C:\Program Files\erl5.5.3\bin,將上面的程序存為tut17.erl,并拷貝到同一個(gè)目錄下。我們將創(chuàng)建兩個(gè)節(jié)點(diǎn),一個(gè)叫ping@dennis,一個(gè)叫pong@dennis,其中dennis是我的機(jī)器名。見(jiàn)下圖:

    采用同樣的命令
    erl -sname ping
    創(chuàng)建ping節(jié)點(diǎn)。然后在pong節(jié)點(diǎn)下執(zhí)行start_pong():


    OK,這樣就在節(jié)點(diǎn)pong上啟動(dòng)了pong進(jìn)程,然后在ping節(jié)點(diǎn)調(diào)用start_ping,傳入?yún)?shù)就是pong@dennis
    tut17:start_ping(pong@dennis).
    執(zhí)行結(jié)果如下圖:

    同樣在pong節(jié)點(diǎn)上也可以看到:


        結(jié)果如我們預(yù)期的那樣,不同節(jié)點(diǎn)上的兩個(gè)進(jìn)程相互通信如此簡(jiǎn)單。我們給模塊tut17增加一個(gè)方法,用于啟動(dòng)遠(yuǎn)程進(jìn)程,也就是調(diào)用spawn(Node,Module,Func,Args)方法:
    start(Ping_Node) ->
        register(pong
    , spawn(tut17, pong, [])),
        spawn(Ping_Node
    , tut17, ping, [3, node()]).
    pong進(jìn)程啟動(dòng)Ping_Node節(jié)點(diǎn)上的進(jìn)程ping。具體結(jié)果不再給出。



        

    posted @ 2007-06-15 17:33 dennis 閱讀(5505) | 評(píng)論 (1)編輯 收藏

        Erlang中的process——進(jìn)程是輕量級(jí)的,并且進(jìn)程間無(wú)共享。查了很多資料,似乎沒(méi)人說(shuō)清楚輕量級(jí)進(jìn)程算是什么概念,繼續(xù)查找中。。。閑話不提,進(jìn)入并發(fā)編程的世界。本文算是學(xué)習(xí)筆記,也可以說(shuō)是《Concurrent Programming in ERLANG》第五張的簡(jiǎn)略翻譯。
    1.進(jìn)程的創(chuàng)建
        進(jìn)程是一種自包含的、分隔的計(jì)算單元,并與其他進(jìn)程并發(fā)運(yùn)行在系統(tǒng)中,在進(jìn)程間并沒(méi)有一個(gè)繼承體系,當(dāng)然,應(yīng)用開(kāi)發(fā)者可以設(shè)計(jì)這樣一個(gè)繼承體系。
        進(jìn)程的創(chuàng)建使用如下語(yǔ)法:
    Pid = spawn(Module, FunctionName, ArgumentList)

    spawn接受三個(gè)參數(shù):模塊名,函數(shù)名以及參數(shù)列表,并返回一個(gè)代表創(chuàng)建的進(jìn)程的標(biāo)識(shí)符(Pid)。
    如果在一個(gè)已知進(jìn)程Pid1中執(zhí)行:
    Pid2 = spawn(Mod, Func, Args)
    那么,Pid2僅僅能被Pid1可見(jiàn),Erlang系統(tǒng)的安全性就構(gòu)建在限制進(jìn)程擴(kuò)展的基礎(chǔ)上。

    2.進(jìn)程間通信
        Erlang進(jìn)程間的通信只能通過(guò)發(fā)送消息來(lái)實(shí)現(xiàn),消息的發(fā)送使用!符號(hào):
    Pid ! Message
        其中Pid是接受消息的進(jìn)程標(biāo)記符,Message就是消息。接受方和消息可以是任何的有效的Erlang結(jié)構(gòu),只要他們的結(jié)果返回的是進(jìn)程標(biāo)記符和消息。
        消息的接受是使用receive關(guān)鍵字,語(yǔ)法如下:
    receive
          Message1 [when Guard1] 
    ->
              Actions1 ;
          Message2 [when Guard2] 
    ->
              Actions2 ;

    end

        每一個(gè)Erlang進(jìn)程都有一個(gè)“郵箱”,所有發(fā)送到進(jìn)程的消息都按照到達(dá)的順序存儲(chǔ)在“郵箱”里,上面所示的消息Message1,Message2,當(dāng)它們與“郵箱”里的消息匹配,并且約束(Guard)通過(guò),那么相應(yīng)的ActionN將執(zhí)行,并且receive返回的是ActionN的最后一條執(zhí)行語(yǔ)句的結(jié)果。Erlang對(duì)“郵箱”里的消息匹配是有選擇性的,只有匹配的消息將被觸發(fā)相應(yīng)的Action,而沒(méi)有匹配的消息將仍然保留在“郵箱”里。這一機(jī)制保證了沒(méi)有消息會(huì)阻塞其他消息的到達(dá)。
        消息到達(dá)的順序并不決定消息的優(yōu)先級(jí),進(jìn)程將輪流檢查“郵箱”里的消息進(jìn)行嘗試匹配。消息的優(yōu)先級(jí)別下文再講。

        如何接受特定進(jìn)程的消息呢?答案很簡(jiǎn)單,將發(fā)送方(sender)也附送在消息當(dāng)中,接收方通過(guò)模式匹配決定是否接受,比如:
    Pid ! {self(),abc}
    給進(jìn)程Pid發(fā)送消息{self(),abc},利用self過(guò)程得到發(fā)送方作為消息發(fā)送。然后接收方:
    receive
      {Pid
    1,Msg} ->

    end
    通過(guò)模式匹配決定只有Pid1進(jìn)程發(fā)送的消息才接受。

    3.一些例子
        僅說(shuō)明下書(shū)中計(jì)數(shù)的進(jìn)程例子,我添加了簡(jiǎn)單注釋:
    -module(counter).
    -compile(export_all).
    % start(),返回一個(gè)新進(jìn)程,進(jìn)程執(zhí)行函數(shù)loop
    start()
    ->spawn(counter, loop,[0]).
    % 調(diào)用此操作遞增計(jì)數(shù)
    increment(Counter)
    ->
        Counter
    !increament.
    % 返回當(dāng)前計(jì)數(shù)值
    value(Counter)
    ->
        Counter
    !{self(),value},
        receive
            {Counter
    ,Value}->
                
    %返回給調(diào)用方
                Value
            end
    .
      
    %停止計(jì)數(shù)      
     stop(Counter)
    ->
         Counter
    !{self(),stop}.
     loop(Val)
    ->
         receive
             
    %接受不同的消息,決定返回結(jié)果
             increament
    ->
                 loop(Val
    +1);
             {From
    ,value}->
                 From
    !{self(),Val},
                 loop(Val);
             stop
    ->
                 true;
             
    %不是以上3種消息,就繼續(xù)等待
             Other
    ->
                 loop(Val)
          end
    .   
                 
                            
            


    調(diào)用方式:
    1> Counter1=counter:start().
    <0.30.0>
    2> counter:value(Counter1).
    0
    3> counter:increment(Counter1).
    increament
    4> counter:value(Counter1).
    1

    基于進(jìn)程的消息傳遞機(jī)制可以很容易地實(shí)現(xiàn)有限狀態(tài)機(jī)(FSM),狀態(tài)使用函數(shù)表示,而事件就是消息。具體不再展開(kāi)

    4.超時(shí)設(shè)置
        Erlang中的receive語(yǔ)法可以添加一個(gè)額外選項(xiàng):timeout,類似:
    receive
       Message1 [when Guard1] 
    ->
         Actions1 ;
       Message2 [when Guard2] 
    ->
         Actions2 ;
       

       after
          TimeOutExpr 
    ->
             ActionsT
    end

    after之后的TimeOutExpr表達(dá)式返回一個(gè)整數(shù)time(毫秒級(jí)別),時(shí)間的精確程度依賴于Erlang在操作系統(tǒng)或者硬件的實(shí)現(xiàn)。如果在time毫秒內(nèi),沒(méi)有一個(gè)消息被選中,超時(shí)設(shè)置將生效,也就是ActionT將執(zhí)行。time有兩個(gè)特殊值:
    1)infinity(無(wú)窮大),infinity是一個(gè)atom,指定了超時(shí)設(shè)置將永遠(yuǎn)不會(huì)被執(zhí)行。
    2) 0,超時(shí)如果設(shè)定為0意味著超時(shí)設(shè)置將立刻執(zhí)行,但是系統(tǒng)將首先嘗試當(dāng)前“郵箱”里的消息。

        超時(shí)的常見(jiàn)幾個(gè)應(yīng)用,比如掛起當(dāng)前進(jìn)程多少毫秒:
    sleep(Time->
      receive
        after 
    Time ->
        true
    end
    .
        比如清空進(jìn)程的“郵箱”,丟棄“郵箱”里的所有消息:
       
    flush_buffer() ->
      receive
        AnyMessage 
    ->
          flush_buffer()
      after 
    0 ->
        true
    end
    .
        將當(dāng)前進(jìn)程永遠(yuǎn)掛起:
      suspend() ->
        receive
        after
            infinity 
    ->
                true
        end
    .
        超時(shí)也可以應(yīng)用于實(shí)現(xiàn)定時(shí)器,比如下面這個(gè)例子,創(chuàng)建一個(gè)進(jìn)程,這個(gè)進(jìn)程將在設(shè)定時(shí)間后向自己發(fā)送消息:
    -module(timer).
    -export([timeout/2,cancel/1,timer/3]).
    timeout(
    Time, Alarm->
       spawn(timer
    , timer, [self(),Time,Alarm]).
    cancel(Timer) 
    ->
       Timer 
    ! {self(),cancel}.
    timer(Pid
    , Time, Alarm->
       receive
        {Pid
    ,cancel} ->
           true
       after 
    Time ->
           Pid 
    ! Alarm
    end
    .

       
    5、注冊(cè)進(jìn)程
        為了給進(jìn)程發(fā)送消息,我們需要知道進(jìn)程的Pid,但是在某些情況下:在一個(gè)很大系統(tǒng)里面有很多的全局servers,或者為了安全考慮需要隱藏進(jìn)程Pid。為了達(dá)到可以發(fā)送消息給一個(gè)不知道Pid的進(jìn)程的目的,我們提供了注冊(cè)進(jìn)程的辦法,給進(jìn)程們注冊(cè)名字,這些名字必須是atom。
        基本的調(diào)用形式:
    register(Name, Pid)
    將Name與進(jìn)程Pid聯(lián)系起來(lái)

    unregister(Name)
    取消Name與相應(yīng)進(jìn)程的對(duì)應(yīng)關(guān)系。

    whereis(Name)
    返回Name所關(guān)聯(lián)的進(jìn)程的Pid,如果沒(méi)有進(jìn)程與之關(guān)聯(lián),就返回atom
    :undefined

    registered()
    返回當(dāng)前注冊(cè)的進(jìn)程的名字列表

    6.進(jìn)程的優(yōu)先級(jí)
    設(shè)定進(jìn)程的優(yōu)先級(jí)可以使用BIFs:
    process_flag(priority, Pri)

    Pri可以是normal、low,默認(rèn)都是normal
    優(yōu)先級(jí)高的進(jìn)程將相對(duì)低的執(zhí)行多一點(diǎn)。

    7.進(jìn)程組(process group)
        所有的ERLANG進(jìn)程都有一個(gè)Pid與一個(gè)他們共有的稱為Group Leader相關(guān)聯(lián),當(dāng)一個(gè)新的進(jìn)程被創(chuàng)建的時(shí)候?qū)⒈患尤胪粋€(gè)進(jìn)程組。最初的系統(tǒng)進(jìn)程的Group Leader就是它自身,因此它也是所有被創(chuàng)建進(jìn)程及子進(jìn)程的Group Leader。這就意味著Erlang的進(jìn)程被組織為一棵Tree,其中的根節(jié)點(diǎn)就是第一個(gè)被創(chuàng)建的進(jìn)程。下面的BIFs被用于操縱進(jìn)程組:
    group_leader()
    返回執(zhí)行進(jìn)程的Group Leader的Pid
    group_leader(Leader, Pid)
    設(shè)置進(jìn)程Pid的Group Leader為進(jìn)程的Leader

    8.Erlang的進(jìn)程模型很容易去構(gòu)建Client-Server的模型,書(shū)中有一節(jié)專門(mén)討論了這一點(diǎn),著重強(qiáng)調(diào)了接口的設(shè)計(jì)以及抽象層次的隔離問(wèn)題,不翻譯了。

    posted @ 2007-06-14 17:12 dennis 閱讀(7158) | 評(píng)論 (0)編輯 收藏

    Erlang logo

    Erlang前世今生


    1982 - 1985

    我們使用了 > 20種語(yǔ)言進(jìn)行了電信行業(yè)的編程實(shí)驗(yàn),結(jié)論是:這樣的語(yǔ)言需要是一門(mén)高度的抽象的語(yǔ)言才能達(dá)到生產(chǎn)力目標(biāo)。(給我們留下印象的有:List,Prolog,Parlog ...)

    1985 - 86

    我們使用Lisp,Prolog,Parlog等語(yǔ)言進(jìn)行了實(shí)驗(yàn),結(jié)論是:這樣的語(yǔ)言需要原生支持的并發(fā)控制和容錯(cuò)處理,并且執(zhí)行模型必須沒(méi)有使用回溯。(排除了List和Prolog.) 而且它必須擁有并發(fā)粒度比如一個(gè)異步的電話進(jìn)程可以用語(yǔ)言的一個(gè)進(jìn)程表示(排除了Parlog)。最后我們不得不開(kāi)發(fā)一門(mén)我們自己的語(yǔ)言,它擁有 Lisp,Prolog和Parlog的特性,但內(nèi)置了并發(fā)和容錯(cuò)處理。

    1987

    第一次使用erlang進(jìn)行實(shí)驗(yàn)。

    1988

    ACS/Dunder(項(xiàng)目)第一階段:外來(lái)用戶使用erlang進(jìn)行PABX(專用自動(dòng)交換分機(jī))功能的原型構(gòu)建, Erlang走出了實(shí)驗(yàn)室!

    1989

     ACS/Dunder(項(xiàng)目)第二階段:重新改造了完整的MD-110系統(tǒng)的1/10,結(jié)果:相比于使用PLEX的構(gòu)建有>>10倍的效率提高!

    1990

     Erlang正式以ISS'90標(biāo)準(zhǔn)發(fā)布,這帶來(lái)不少的新用戶,比如Bellcore。

    1991

    Erlang發(fā)布了更快的版本實(shí)現(xiàn)給用戶,Erlang應(yīng)用于電信'91(項(xiàng)目?),更多功能比如編譯器、圖形接口等。

    1992

     更多的新用戶,許多高速發(fā)展的項(xiàng)目。Erlang可以運(yùn)行于VxWorks,PC,Macintosh等系統(tǒng)。有三個(gè)應(yīng)用使用了ISS'92標(biāo)準(zhǔn)的Erlang。

    1993

     分布式支持加進(jìn)了Erlang,這使得erlang可以運(yùn)行一個(gè)自發(fā)系統(tǒng)在不同的硬件上。決定向外部發(fā)布Erlang的實(shí)現(xiàn),從愛(ài)立信分離出獨(dú)立的部門(mén)開(kāi)始維護(hù)和支持Erlang的實(shí)現(xiàn)和Erlang工具的開(kāi)發(fā)工作。

    posted @ 2007-06-14 09:28 dennis 閱讀(2134) | 評(píng)論 (2)編輯 收藏

        讀erlang.org上面的Erlang Course四天教程
    1.數(shù)字類型,需要注意兩點(diǎn)
    1)B#Val表示以B進(jìn)制存儲(chǔ)的數(shù)字Val,比如
    7> 2#101.
    5
    進(jìn)制存儲(chǔ)的101就是10進(jìn)制的5了
    2)$Char表示字符Char的ascii編碼,比如$A表示65

    2.比較難以翻譯的概念——atom,可以理解成常量,它可以包含任何字符,以小寫(xiě)字母開(kāi)頭,如果不是以小寫(xiě)字母開(kāi)頭或者是字母之外的符號(hào),需要用單引號(hào)包括起來(lái),比如abc,'AB'

    3.另一個(gè)概念——Tuple,有人翻譯成元組,可以理解成定長(zhǎng)數(shù)組,是Erlang的基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)之一:
    8> {1,2,3,4,5}.
    {
    1,2,3,4,5}
    9> {a,b,c,1,2}.
    {a
    ,b,c,1,2}
    10> size({1,2,3,a,b,c}).
    6
    內(nèi)置函數(shù)size求長(zhǎng)度,元組可以嵌套元組或者其他結(jié)構(gòu)。下面所講的列表也一樣。

    4.另外一個(gè)基礎(chǔ)數(shù)據(jù)結(jié)構(gòu)就是各個(gè)語(yǔ)言都有的list(列表),在[]內(nèi)以,隔開(kāi),可以動(dòng)態(tài)改變大小,
        [123, xyz]
        [
    123, def, abc]
        [{person
    , 'Joe', 'Armstrong'},
            {person
    , 'Robert', 'Virding'},
            {person
    , 'Mike', 'Williams'}
        ]
    可以使用內(nèi)置函數(shù)length求列表大小。以""包含的ascii字母代表一個(gè)列表,里面的元素就是這些字母的ascii值,比如"abc"表示列表[97,98,99]。

    5.通過(guò)這兩個(gè)數(shù)據(jù)結(jié)構(gòu)可以組合成各種復(fù)雜結(jié)構(gòu),與Lisp的cons、list演化出各種結(jié)構(gòu)一樣的奇妙,Erlang也可以當(dāng)作是操作列表的語(yǔ)言。

    6.Erlang中變量有兩個(gè)特點(diǎn):
    1)變量必須以大寫(xiě)字母或者下劃線開(kāi)頭,可以包含字母、下劃線和@
    2)變量只能綁定一次,也就是所謂的Single Assignment。或者以一般的說(shuō)法就是只能賦值一次,其實(shí)Erlang并沒(méi)有賦值這樣的概念,=號(hào)也是用于驗(yàn)證匹配。

    7.模式匹配——Pattern Matching,Erlang的模式匹配非常強(qiáng)大,看了buaawhl的《Erlang語(yǔ)法提要》的介紹,模式匹配的功能不僅僅在課程中介紹的數(shù)據(jù)結(jié)構(gòu)的拆解,在程序的分派也扮演重要角色,或者說(shuō)Erlang的控制的流轉(zhuǎn)是通過(guò)模式匹配來(lái)實(shí)現(xiàn)的。具體功能參見(jiàn)鏈接,給出書(shū)中拆解列表的例子:
        [A,B|C] = [1,2,3,4,5,6,7]
            Succeeds 
    - binds A = 1, B = 2,
            C 
    = [3,4,5,6,7]
        
        [H
    |T] = [1,2,3,4]
            Succeeds 
    - binds H = 1, T = [2,3,4]
        
        [H
    |T] = [abc]
            Succeeds 
    - binds H = abc, T = []
        
        [H
    |T] = []
            Fails

    下面會(huì)給出更多模式匹配的例子,給出一個(gè)模塊用來(lái)計(jì)算列表等

    8.Erlang中函數(shù)的定義必須在一個(gè)模塊內(nèi)(Module),并且模塊和函數(shù)的名稱都必須是atom,函數(shù)的參數(shù)可以是任何的Erlang類型或者數(shù)據(jù)結(jié)構(gòu),函數(shù)要被調(diào)用需要從模塊中導(dǎo)出,函數(shù)調(diào)用的形式類似:
    moduleName:funcName(Arg1,Arg2,...).
    寫(xiě)我們的第一個(gè)Erlang程序,人見(jiàn)人愛(ài)的Hello World:
    -module(helloWorld).
    -export([run/1]).
    run(Name)
    ->
        io
    :format("Hello World ~w~n",[Name]).
    存為helloWorld.erl,在Erlang Shell中執(zhí)行:
    2> c(helloWorld).
    {ok
    ,helloWorld}
    3> helloWorld:run(dennis).
    Hello World dennis
    ok
    打印出來(lái)了,現(xiàn)在解釋下程序構(gòu)造,
    -module(helloWorld).
    這一行聲明了模塊helloWorld,函數(shù)必須定義在模塊內(nèi),并且模塊名稱必須與源文件名相同。
    -export([run/1]).
    而這一行聲明導(dǎo)出的函數(shù),run/1指的是有一個(gè)參數(shù)的run函數(shù),因?yàn)镋rlang允許定義同名的有不同參數(shù)的多個(gè)函數(shù),通過(guò)指定/1來(lái)說(shuō)明要導(dǎo)出的是哪個(gè)函數(shù)。
    接下來(lái)就是函數(shù)定義了:
    run(Name)->
        io
    :format("Hello World ~w~n",[Name]).
    大寫(xiě)開(kāi)頭的是變量Name,調(diào)用io模塊的format方法輸出,~w可以理解成占位符,將被實(shí)際Name取代,~n就是換行了。注意,函數(shù)定義完了要以句號(hào).結(jié)束。然后執(zhí)行c(helloWorld).編譯源代碼,執(zhí)行:
    helloWorld:run(dennis);

    9.內(nèi)置的常用函數(shù):
        date()
        
    time()
        
    length([1,2,3,4,5])
        size({a
    ,b,c})
        atom_to_list(an_atom)
        list_to_tuple([
    1,2,3,4])
        integer_to_list(
    2234)
        tuple_to_list({})
        hd([1,2,3,4])  %輸出1,也就是列表的head,類似Lisp的car
        tl([1,2,3,4])  %輸出[2,3,4],也就是列表的tail,類似List的cdr

    10.常見(jiàn)Shell命令:
    1)h(). 用來(lái)打印最近的20條歷史命令
    2)b(). 查看所有綁定的變量
    3) f(). 取消(遺忘)所有綁定的變量。
    4) f(Val).  取消指定的綁定變量
    5) e(n).   執(zhí)行第n條歷史命令
    6) e(-1).  執(zhí)行上一條shell命令

    11.又一個(gè)不知道怎么翻譯的概念——Guard。翻譯成約束?呵呵。用于限制變量的類型和范圍,比如:
         number(X)    - X 是數(shù)字
        integer(X)    
    - X 是整數(shù)
        float(X)    
    - X 是浮點(diǎn)數(shù)
        atom(X)        
    - X 是一個(gè)atom
        tuple(X)    
    - X 是一個(gè)元組
        list(X)        
    - X 是一個(gè)列表
        
        
    length(X) == 3    - X 是一個(gè)長(zhǎng)度為3的列表
        size(X) 
    == 2    - X 是一個(gè)長(zhǎng)度為2的元組
        
        X 
    > Y + Z    - X >Y+Z
        X 
    == Y        - X 與Y相等
        X 
    =:= Y        - X 全等于Y
        (比如: 
    1 == 1.0 成功
                   
    1 =:= 1.0 失敗)
    為了方便比較,Erlang規(guī)定如下的比較順序:
    number < atom < reference < port < pid < tuple < list
    其中pid就是process的id。

    12.忘了介紹apply函數(shù),這個(gè)函數(shù)對(duì)于熟悉javascript的人來(lái)說(shuō)很親切,javascript實(shí)現(xiàn)mixin就得靠它,它的調(diào)用方式如下:
    apply(Mod, Func, Args),三個(gè)參數(shù)分別是模塊、函數(shù)以及參數(shù)列表,比如調(diào)用我們的第一個(gè)Erlang程序:
    apply(helloWorld,run,[dennis]).
    13.if和case語(yǔ)句,if語(yǔ)句的結(jié)構(gòu)如下:
    if
    Guard1 ->
    Sequence1 ;
    Guard2 ->
    Sequence2 ;
    ...
    end
    而case語(yǔ)句的結(jié)構(gòu)如下:
    case Expr of
    Pattern1 [when Guard1] 
    -> Seq1;
    Pattern2 [when Guard2] 
    -> Seq2;

    PatternN [when GuardN] 
    -> SeqN
    end


    if和case語(yǔ)句都有一個(gè)問(wèn)題,就是當(dāng)沒(méi)有模式匹配或者Grard都是false的時(shí)候會(huì)導(dǎo)致error,這個(gè)問(wèn)題case可以增加一個(gè)類似java中default的:
    case Fn of

       _ 
    ->
       true
    end
    通過(guò)_指代任意的Expr,返回true,而if可以這樣:
    if
      

      true 
    ->
       true
    end
    一樣的道理。case語(yǔ)句另一個(gè)需要注意的問(wèn)題就是變量范圍,每個(gè)case分支中定義的變量都將默認(rèn)導(dǎo)出case語(yǔ)句,也就是在case語(yǔ)句結(jié)束后可以被引用,因此一個(gè)規(guī)則就是每個(gè)case分支定義的變量應(yīng)該一致,不然算是非法的,編譯器會(huì)給出警告,比如:
    f(X) ->
    case g(X) of
    true 
    -> A = h(X), B = A + 7;
    false 
    -> B = 6
    end
    ,
    h(A)
    .

    如果執(zhí)行true分支,變量A和變量B都被定義,而如果執(zhí)行的false分支,只有變量B被定義,可在case語(yǔ)句執(zhí)行后,h(A)調(diào)用了變量A,這是不安全的,因?yàn)樽兞緼完全可能沒(méi)有被定義,編譯器將給出警告
    variable 'A' unsafe in 'case' (line 10)



    14.給出一些稍微復(fù)雜的模型匹配例子,比如用于計(jì)算數(shù)字列表的和、平均值、長(zhǎng)度、查找某元素是否在列表中,我們把這個(gè)模塊定義為list:
    -module(list).
    -export([average/1,sum/1,len/1,double/1,member/2]).
    average(X)
    ->sum(X)/len(X).
    sum([H
    |T]) when number(H)->H+sum(T);
    sum([])
    ->0.
    len([_
    |T])->1+len(T);
    len([])
    ->0.
    double([H
    |T]) -> [2*H|double(T)];
    double([]) 
    -> [].
    member(H
    , [H|_]) -> true;
    member(H
    , [_|T]) -> member(H, T);
    member(_
    , []) -> false.
                    

    細(xì)細(xì)體會(huì),利用遞歸來(lái)實(shí)現(xiàn),比較有趣,這其實(shí)與Lisp中利用尾遞歸來(lái)實(shí)現(xiàn)迭代是一樣的道理,[H|T]的形式類似Lisp中的car、cdr操作。_用于指代任意的變量,當(dāng)我們只關(guān)注此處有變量,但并不關(guān)心變量的值的時(shí)候使用。用分號(hào);來(lái)說(shuō)明是同一個(gè)函數(shù)定義,只是不同的定義分支,通過(guò)模式匹配來(lái)決定調(diào)用哪個(gè)函數(shù)定義分支。
    另一個(gè)例子,計(jì)算各種圖形的面積,也是課程中給出的例子:

    -module(mathStuff).
    -export([factorial/1,area/1]).
    factorial(
    0)->1;
    factorial(N) when N
    >0->N*factorial(N-1).
    %計(jì)算正方形面積,參數(shù)元組的第一個(gè)匹配square    
    area({square
    , Side}) ->
        Side 
    * Side;
    %計(jì)算圓的面積,匹配circle  
    area({circle
    , Radius}) ->
       
    % almost :-)
       
    3 * Radius * Radius;
    %計(jì)算三角形的面積,利用海倫公式,匹配triangle 
    area({triangle
    , A, B, C}) ->
       S 
    = (A + B + C)/2,
    math
    :sqrt(S*(S-A)*(S-B)*(S-C));
    %其他
    area(Other) 
    ->
       {invalid_object
    , Other}.

    執(zhí)行一下看看:
    1> c(mathStuff).
    {ok
    ,mathStuff}
    2> mathStuff:area({square,2}).
    4
    3> mathStuff:area({circle,2}).
    12
    4> mathStuff:area({triangle,2,3,4}).
    2.90474
    5> mathStuff:area({other,2,3,4}).
    {invalid_object
    ,{other,2,3,4}}

    Erlang使用%開(kāi)始單行注釋。

    posted @ 2007-06-13 14:36 dennis 閱讀(29178) | 評(píng)論 (4)編輯 收藏

    看到天涯上的這個(gè)帖子:誰(shuí)來(lái)救救我們的孩子?——400位父親泣血呼救。我難以呼吸,我無(wú)法相信這殘酷的現(xiàn)實(shí)。在21世紀(jì)的今天,竟然還有類似奴隸這樣的現(xiàn)象出現(xiàn),這就是我的祖國(guó),這就是和諧社會(huì)。我?guī)筒涣四切┖⒆樱抑缓冒堰@個(gè)帖子寫(xiě)在blog里,讓更多人知道,讓更多人思考。

    posted @ 2007-06-12 11:40 dennis 閱讀(695) | 評(píng)論 (1)編輯 收藏

    習(xí)題2.17,直接利用list-ref和length過(guò)程
    (define (last-pair items)
      (list (list
    -ref items (- (length items) 1))))

    習(xí)題2.18,采用迭代法
    (define (reverse-list items)
      (define (reverse
    -iter i k)
        (
    if (null? i) k (reverse-iter (cdr i) (cons (car i) k))))
      (reverse
    -iter items ()))
    習(xí)題2.20,如果兩個(gè)數(shù)的奇偶相同,那么他們的差模2等于0,根據(jù)這一點(diǎn)可以寫(xiě)出:
    (define (same-parity a . b)
      (define (same
    -parity-temp x y)
      (cond ((
    null? y) y)
            ((
    = (remainder (- (car y) x) 20)
             (cons (car y) (same
    -parity-temp x (cdr y))))
            (
    else
               (same
    -parity-temp x (cdr y)))))
      (cons a (same
    -parity-temp a b)))
    利用了基本過(guò)程remainder取模

    習(xí)題2.21,遞歸方式:
    (define (square-list items)
      (
    if (null? items)
          items 
          (cons (square (car items)) (square
    -list (cdr items)))))
    利用map過(guò)程:
    (define (square-list items)
      (map square items))

    習(xí)題2.23,這與ruby中的each是一樣的意思,將操作應(yīng)用于集合的每個(gè)元素:
    (define (for-each proc items)
      (define (
    for-each-temp proc temp items)
      (
    if (null? items)
          #t
          (
    for-each-temp proc (proc (car items)) (cdr items))))
      (
    for-each-temp proc 0 items))
    最后返回true

    習(xí)題2.24,盒子圖就不畫(huà)了,麻煩,解釋器輸出:
    Welcome to DrScheme, version 360.
    Language: Standard (R5RS).
    > (list 1 (list 2 (list 3 4)))
    (
    1 (2 (3 4)))
    樹(shù)形狀應(yīng)當(dāng)是這樣
                   . 
    /\
    / \
    1 .
    /\
    / \
    2 .
    /\
    / \
    3 4
    習(xí)題2.25,
    第一個(gè)list可以表示為(list 1 3 (list 5 7) 9)
    因此取7的操作應(yīng)當(dāng)是:
    (car (cdr (car (cdr (cdr (list 1 3 (list 5 79))))))
    第二個(gè)list表示為:(list (list 7))
    因此取7操作為:
    (car (car (list (list 7))))

    第三個(gè)list可以表示為:
    (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7))))))
    因此取7的操作為:
    (define x (list 1 (list 2 (list 3 (list 4 (list 5 (list 6 7)))))))
    (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr (car (cdr x))))))))))))
    夠恐怖!-_-

    習(xí)題2.26,純粹的動(dòng)手題,就不說(shuō)了
    習(xí)題2.27,在reverse的基礎(chǔ)上進(jìn)行修改,同樣采用迭代,比較難理解:

    (define (deep-reverse x)
      (define (reverse
    -iter rest result)
        (cond ((null? rest) result)
              ((
    not (pair? (car rest)))
               (reverse
    -iter (cdr rest)
                     (cons (car rest) result)))
              (
    else
               (reverse
    -iter (cdr rest)
                     (cons (deep
    -reverse (car rest)) result)))
               ))
      (reverse
    -iter x ()))

    習(xí)題2.28,遞歸,利用append過(guò)程就容易了:
    (define (finge x)
      (cond ((pair? x) (append (finge (car x)) (finge (cdr x))))
            ((null? x) ())
            (
    else (list x))))

    習(xí)題2.29,這一題很明顯出來(lái)的二叉活動(dòng)體也是個(gè)層次性的樹(shù)狀結(jié)構(gòu)
    1)很簡(jiǎn)單,利用car,cdr
    (define (left-branch x)
      (car x))
    (define (right
    -branch x)
      (car (cdr x)))
    (define (branch
    -length b)
      (car b))
    (define (branch
    -structure b)
      (car (cdr b)))

    2)首先需要一個(gè)過(guò)程用于求解分支的總重量:
    (define (branch-weight branch)
      (let ((structure (branch
    -structure branch)))
        (
    if (not (pair? structure))
            structure
            (total
    -weight structure))))
    (define (total
    -weight mobile)
      (
    + (branch-weight (left-branch mobile))
         (branch
    -weight (right-branch mobile))))

    利用這個(gè)過(guò)程寫(xiě)出balanced?過(guò)程:
    (define (torque branch)
      (
    * (branch-length branch) (branch-weight branch)))
    (define (balanced? mobile)
      (
    = (torque (left-branch mobile))
         (torque (right
    -branch mobile))))

    3)選擇函數(shù)和定義函數(shù)提供了一層抽象屏蔽,其他函數(shù)都是建立在這兩個(gè)基礎(chǔ)上,因此需要改變的僅僅是selector函數(shù):
    (define (right-branch mobile) (cdr mobile))
    (define (branch
    -structure branch) (cdr branch))

    習(xí)題2.30:
    (define (square-tree tree)
      (cond ((null? tree) tree)
            ((
    not (pair? tree)) (square tree))
            (
    else
               (cons (square
    -tree (car tree)) (square-tree (cdr tree))))))
    (define (square
    -tree2 tree)
      (map (
    lambda(x)
             (
    if (pair? x)
                 (square
    -tree x)
                 (square x))) tree))

    習(xí)題2.31,進(jìn)一步抽象出map-tree,與map過(guò)程類似,將proc過(guò)程作用于樹(shù)的每個(gè)節(jié)點(diǎn):
    (define (tree-map proc tree)
      (cond ((null? tree) tree)
            ((
    not (pair? tree)) (proc tree))
            (
    else
               (cons (tree
    -map proc (car tree)) (tree-map proc (cdr tree))))))
    (define (square
    -tree3 tree)
      (tree
    -map square tree))

    習(xí)題2.32,通過(guò)觀察,rest總是cdr后的子集,比如對(duì)于(list 1 2 3),連續(xù)cdr出來(lái)的是:
    (2 3)
    (3)
    ()
    其他的5個(gè)子集應(yīng)該是car結(jié)果與這些子集組合的結(jié)果,因此:
    (define (subsets s)
      (
    if (null? s)
          (list s)
          (let ((rest (subsets (cdr s))))
            (append rest (map (
    lambda(x) (cons (car s) x)) rest)))))


    posted @ 2007-06-12 09:55 dennis 閱讀(1083) | 評(píng)論 (2)編輯 收藏

    僅列出標(biāo)題
    共56頁(yè): First 上一頁(yè) 38 39 40 41 42 43 44 45 46 下一頁(yè) Last 
    主站蜘蛛池模板: 亚洲av成人中文无码专区| 精品97国产免费人成视频 | 成在线人免费无码高潮喷水| 曰批全过程免费视频在线观看| 伊人久久大香线蕉亚洲五月天| 亚洲真人无码永久在线观看| 最近新韩国日本免费观看| 国产日产亚洲系列最新| 亚洲乱色熟女一区二区三区蜜臀| 免费看搞黄视频网站| 亚洲一区二区三区乱码A| 亚洲永久网址在线观看| 亚州免费一级毛片| 亚洲成AV人片在| 一级做a爰性色毛片免费| 热99re久久精品精品免费| 亚洲视频国产视频| 成人无码a级毛片免费| 亚洲国产精品成人久久蜜臀| 中文日韩亚洲欧美制服| 免费在线观看污网站| 亚洲成人在线免费观看| 在线观看人成视频免费无遮挡 | 国产精品永久免费10000| 亚洲国产成人片在线观看无码| 日本一区二区三区在线视频观看免费| 最近中文字幕免费mv视频7| 亚洲最大中文字幕| 亚洲成人免费在线| 久久91亚洲人成电影网站| 乱淫片免费影院观看| 免费在线视频一区| 精品亚洲视频在线| 午夜a级成人免费毛片| 亚洲免费福利在线视频| 无码国产精品一区二区免费式影视| 亚洲AV成人片色在线观看| a成人毛片免费观看| 亚洲色欲久久久综合网| 国产精品极品美女自在线观看免费 | 免费在线观看日韩|