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

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

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

    Read Sean

    Read me, read Sean.
    posts - 508, comments - 655, trackbacks - 9, articles - 4

    用Scala解Hanoi塔

    Posted on 2009-11-23 19:20 laogao 閱讀(2614) 評論(3)  編輯  收藏 所屬分類: On Java 、Programming in General 、Other Languages

    到處吹噓Scala很長時間了,卻一直沒有在自己的blog上增加過任何相關內容,今天就來補一補。當然,Scala的基本特性就不多廢話了,網上已經有相當多的資料,如果懶得google,只想看完本文,那么你只需要知道它是一門以JVM為目標運行環境的靜態編程語言(當然,Scala官方也有.NET版,但已不是其重點),同時具備面向對象和函數式編程語言的特點。本文將通過一個簡單的示例,展示Scala的FP能力,其中十分heavy的用到了implicit隱式轉換和模式匹配。

    代碼是從guithub的gist上抄的,簡單改了改,原始代碼見: http://gist.github.com/66925

    import scala.reflect.Manifest
      
    def simpleName(m:Manifest[_]):String 
    = {
      val name 
    = m.toString
      name.substring(name.lastIndexOf(
    '$')+1)
    }
      
    trait Num
    final class Succ[Pre<:Num] extends Num
    final class _1 extends Num
    type _2 
    = Succ[_1]
    type _3 
    = Succ[_2]
    type _4 
    = Succ[_3]
     
    case class Move[N<:Num,A,B,C]()

    implicit def move1[A,B,C](implicit a:Manifest[A], b:Manifest[B]) : Move[_1,A,B,C] 
    = {
      System.out.println(
    "Move from " + simpleName(a) + " to " + simpleName(b))
      
    null
    }
     
    implicit def moveN[P
    <:Num,A,B,C](implicit m1:Move[P,A,C,B], m2:Move[_1,A,B,C], m3:Move[P,C,B,A]) : Move[Succ[P],A,B,C] = null
      
    def run[N
    <:Num,A,B,C](implicit m:Move[N,A,B,C]) = null
      
    case class Left()
    case class Center()
    case class Right()
      
    run[_3,Left,Right,Center]

     

    這段代碼解決的是經典的漢諾塔問題,通過一根中柱,將左柱上64個大小依次疊加的圓盤全部移動到右柱,要求整個過程中每次只能移動一個圓盤,且每個圓盤只能獨立占據一根柱子或是疊加在比自身更大的圓盤上。

    簡單分析一下就知道,這是一個遞歸問題(FP的英雄特長):

    • 當只有1個圓盤時,不用通過中柱,直接可以從左柱移動到右柱;
    • 當有2個圓盤時,將小盤移動到中柱,剩下的大盤移動到右柱,再從中柱把小盤移動到右柱;
    • 當有3個圓盤時,先移動2個圓盤到中柱,再移動大盤到右柱,再移動2個圓盤到右柱;
    • ...

    很容易發現一個pattern,那就是移動N(N>1)個圓盤,可以通過以下三個步驟:

    1. 移動N-1個圓盤,從左柱到中柱;
    2. 移動剩下的1個圓盤,從左柱到右柱;
    3. 移動N-1個圓盤,從中柱到右柱。

    在解釋代碼之前,先說說Scala的implicit隱式轉換,這是一個非常powerful的idea,當Scala編譯器發現類型不匹配,它不會直接fail,而是嘗試從代碼中指定的,在scope內的implicit轉換定義,來替換問題對象或表達式以滿足類型要求,當然,為了避免歧義,同一時刻Scala需要找到唯一的一個滿足條件的implicit定義。

    我們的代碼首先定義了一個取得友好類名的方法,不去深究它,然后定義了一個正整數的序列,也不去深究它了,你只需要當作他們是正整數就好,接觸過FP的同學應該對此類定義不陌生,接下來定義了如下3個支持implicit傳入參數的方法:

    1. implicit def move1[A,B,C](implicit a:Manifest[A], b:Manifest[B]) : Move[_1,A,B,C]
    2. implicit def moveN[P<:Num,A,B,C]( implicit
      m1:Move[P,A,C,B],
      m2:Move[_1,A,B,C],
      m3:Move[P,C,B,A]
      ) : Move[Succ[P],A,B,C]
    3. def run[N<:Num,A,B,C](implicit m:Move[N,A,B,C])

    含義分別是:

    1. 當需要Move[_1,A,B,C]值時,可以找我幫忙(我有個side-effect,那就是輸出移動指令);
    2. 當需要Move[Succ[P],A,B,C]時,可以找我幫忙;
    3. 運行我,我接受Move[N,A,B,C]類型的參數。

    簡單說明:Scala用[]表示類型參數,區別于Java的<>,另外,Scala的類型聲明在變量/函數定義之后。Move[_,A,B,C]的含義是通過C,從A移動圓盤到B。

    我們來模擬運行一下,為了演示效果,用一個中等復雜的數目,3個圓盤,從Left移動到Right。

    run[_3,Left,Right,Center],對應Move[Succ[_2],Left,Right,Center],于是展開成三個Move:

    Move[_2,Left,Center,Right]即Move[Succ[_1],Left,Center,Right]
    Move[_1,Left,Right,Center]
    Move[_2,Center,Right,Left]即Move[Succ[_1],Center,Right,Left]

    然后繼續展開Move[_2,Left,Center,Right]和Move[_2,Center,Right,Left],得到:

    Move[_1,Left,Right,Center]
    Move[_1,Left,Center,Right]
    Move[_1,Right,Center,Left]
    --------------------------
    Move[_1,Left,Right,Center]
    --------------------------
    Move[_1,Center,Left,Right]
    Move[_1,Center,Right,Left]
    Move[_1,Left,Right,Center]

    這個時候已經全部都匹配Move[_1,A,B,C],于是我們很容易得到以下輸出:

    Move from Left to Right
    Move from Left to Center
    Move from Right to Center
    Move from Left to Right
    Move from Center to Left
    Move from Center to Right
    Move from Left to Right

    希望本文能帶給Scala初學者一些感性認識和啟發。


    Feedback

    # re: 用Scala解Hanoi塔  回復  更多評論   

    2009-11-24 16:28 by 大胃
    歡迎大家參與討論,我會不定期刪除自言自語式的、軟廣告式的、和主題無關的、沒有營養的回復。

    # re: 用Scala解Hanoi塔  回復  更多評論   

    2010-06-11 16:18 by 大胃
    新發表一篇文章,歡迎前往討論
    http://laogao.me/blog/view/8

    # re: 用Scala解Hanoi塔  回復  更多評論   

    2012-05-18 23:14 by Freewind
    我謹代表群內171位scalaer,熱切希望你加入到scala熱情交流群: 132569382(QQ群)
    主站蜘蛛池模板: 一个人在线观看视频免费| 午夜免费福利小电影| 99精品全国免费观看视频| 亚洲精品中文字幕乱码影院| 久久国产精品国产自线拍免费| 亚洲无av在线中文字幕| 尤物视频在线免费观看| 亚洲一区二区三区香蕉| baoyu777永久免费视频 | 国产亚洲精彩视频| 免费观看美女裸体网站| 99亚洲乱人伦aⅴ精品| 日韩中文无码有码免费视频| 色综合久久精品亚洲国产| 又爽又黄无遮挡高清免费视频 | 妞干网在线免费视频| 亚洲天堂男人影院| 国产精品嫩草影院免费| 免费观看四虎精品成人| 亚洲人成在线播放网站| 免费不卡在线观看AV| 亚洲a级在线观看| 国产免费资源高清小视频在线观看| 麻豆一区二区三区蜜桃免费| 亚洲一区二区三区免费在线观看| 麻豆最新国产剧情AV原创免费| 亚洲熟妇AV一区二区三区浪潮| 国产免费av片在线播放| 国产特黄一级一片免费| 99人中文字幕亚洲区| 最新69国产成人精品免费视频动漫 | 久久国产色AV免费观看| 亚洲欧美黑人猛交群| 区三区激情福利综合中文字幕在线一区亚洲视频1 | 9久9久女女免费精品视频在线观看| 国产精品亚洲专区无码唯爱网| 中文字幕精品亚洲无线码一区应用| 久久不见久久见免费视频7| 亚洲AV香蕉一区区二区三区| 中文字幕亚洲一区二区三区| 久久久久久精品免费看SSS|