天天看點

函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

@函數式程式設計中的戰鬥機(二) —運用elm語言MUV設計模式做一個簡單的應用執行個體

函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

1 elm語言設計模式的特點

1.1 面向對象設計模式的特點

每種程式設計語言都有其獨特的文法和優缺點,進而導緻與衆不同的設計模式和固定架構。面向對象程式設計因其竭力接近和模拟現實世界的多态和繼承,導緻面向對象産生了工廠架構等多種設計模式。這些設計的多樣性,對于面向對象程式設計的老手來說,條條大路通羅馬,采用那種設計模式都無礙于其實作最終的目标。而對于新手而言,衆多面向對象的設計模式令其眼花缭亂無所适從。是以,差別不在于采取的設計模式優劣之分,而在于對程式設計基礎和程式設計藝術的了解深度。

1.2 函數式程式設計設計模式的特點

面向對象設計模式衆多,那麼函數式程式設計的設計模式又如何呢?

函數式程式設計強調功能的抽象、代碼的簡潔、可讀性以及可以重複利用的特點。特别是柯裡化(curry)後的功能函數嵌套,可以堆積木般産生許多創造力和生産力。是以函數式程式設計的設計模式遵循這樣一個原則:凡有利于引導開發者在實作目标的過程中,不知不覺把功能進一步抽象成為子產品函數,在實作目的的同時也完成子產品的建構,就是好的設計模式。有點象生産汽車的智能化工廠,在組裝出一輛高品質的汽車同時,也完成了組裝線的設計生産,這就是函數式程式設計的設計模式。

要實作引導的效果,必定不能就面向對象程式設計的随心所欲:萬物皆對象,見天地人是對象,見蛇蟲鼠蟻也是對象,分分鐘建個類,父類子類繼承、方法屬性引用,創造出自己的世界,甚至不管這個世界是真實世界的反映,還是無關現實。

函數式程式設計的模式天生是嚴謹固定的,因為函數式程式設計的基礎起源是數學中的範疇學,而數學是嚴謹可推理的。一個功能子產品的抽象必然是經過數學分析推敲後的提煉,而并非文學想象中的發散性思維。

函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

1.3 elm語言的“MUV”設計模式

這種數學的嚴謹在elm語言的設計模式中展現得淋漓盡緻,甚至苛刻。Elm語言設計模式嚴格限定為MUV架構。

其中“M”是指“model”模型,相當于react或Vue中的“state”狀态。說是狀态有點不恰當,因為react或Vue中強調的是元件概念,而“元件+狀态=對象”,對象是面對象程式設計的範式。Elm作為函數式程式設計的範式,“M”就定義為模型,模型可以是一個數、一個字元,甚至一個複雜的函數,但是一就是一,純淨沒有副作用。模型是程式代碼的核心,所有的功能變化,都是圍繞模型展開。

“U”指的是“update”更新,相當于電腦CPU或發動機引擎,也是一個函數,内置各種操作,但必須以收到指令為前提。指令可以是滑鼠或鍵盤的操作,可以是内置時鐘的定時到點,POST或GET到的一段JSON資料,甚至是NOTHING。隻有收到動作或訊息,update引擎就一絲不苟地按照内置的流程規定,對模型進行操作,輸出一個全新的模型。

“V”是指“view”界面,衆所周知,elm是用于前端的函數式程式設計語言,也是可以直接應用于生産系統的語言,它是為取代javascript、Html和Css三劍客混搭而來,怎麼能少得了前端界面的生成功能?View其實也是一個函數,類似于react中的render,但它用的不是JSX文法,而是更易懂和嚴謹的函數文法。想象一個,一個Html頁面就是一個View函數,随時調用,多麼美妙的事情。

“MUV”構成了elm函數式設計的固定模式,每段程式、每個子產品都以這三個結構為核心,大結構中有小結構、小結構中有微結構。有如分形與混沌,又如須彌世界與大千世界,elm的世界就是如此堅固又紮實地建構起來。

随了MUV外,還有些輔助的函數,如Msg代表消息行動,依附于“U”,Init代表初始化函數,依附于“M”,還有main函數,通常是程式啟動的開始。

“MUV”結構中,資料是單向流動的,消息動作由外界中來,“U”收到後發動引擎,對“M”進行修改和更新。而“V”依據“M”的更新而生成界面。由于elm和react一樣,也是運用了虛拟DOM的技術,是以對于真實Html頁面的渲染速度更快更強。

函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

2 MVU模式實作一個滑鼠點選計數器執行個體

2.1 導入基本庫

首先是導入一些基本的标準庫,包括了Html頁面虛拟Dom、浏覽器操作Browser、滑鼠鍵盤事件的Events庫,這些庫都是elm内置的,并非Javascript庫。要使用javascript庫與之互動溝通,需要通過一種被稱為“Port”碼頭的簡單技巧實作,elm之是以這樣做,是有意要把elm函數式程式設計與多範式的javascrip隔開,保持純淨,不受其影響。

Import Browser
Import Html exposing (Html,button,text)
Import Html.Events exposing (onClick)
           

2.2 啟動主程式和聲明模型初始化

使用Browser庫建立一個沙箱,其中聲明了 “MUV”架構,模型是一個數字,初始值設為0。在沙箱中和init : Model中有兩次初始值的聲明,以筆者經驗,在sandbox中的聲明會優先,如sandbox中init = 10,而随後的init : Model中再次聲明為0,實際運作時數字會以10為初始值。

--Main

Main =
  Browser.sandbox { init = 0, model = model ,update = update, view = view }

-- Model
Type alias Model = Int

Init : Model
Init = 
  0
           

2.3 聲明“U”模型更新引擎

引擎先是聲明一個Msg函數,裡面有Increment“加”和Decrement“減”兩個行為,注意:隻是純聲明,并不說明細節,細節在下列的Case中再行說明。Elm語言有個特定,聲明類的函數表達如同結論在前,論點在後的論述文寫法,先講結論,再一個個細節敲定,這是一種架構在前的系統性思維。在随後的 update類型簽名中,明确看到update引擎是從msg發起,作用于model,再次作用于model三個動作順序。然後是具體的細節敲定:通過 case of msg文法,把increment敲定為model+1,而decrement敲定為model-1,把結論和論據都完滿收尾。

-- UPDATE

Type Msg = Increment | Decrement

Update msg -> model ->model
Update msg model = 
  Case msg of 
    Increment ->
      Model  +  1

    Decrement ->
      Model  -  1
           
函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

2.4 聲明“V”生成界面

View還是聲明式類型簽名,model直接生成Html界面。在界面語言中可以看到函數式表示法的痕迹,先是div []函數,然後是buttong[]函數,再是text 函數。Div用于布局和層次,button 用于按鍵,按鍵的作用是 Decrement或 Increment,而text用于顯示文字。中間的text 顯示是把模型(一個數字)直接轉化為字元串文字顯示出來。

-- VIEW

View : Model -> Html Msg
View : model = 
  Div []
   [  button [  onClick Decrement  ] [  text “-”  ]
   ,  div []  [  text  (String.fromInt model) ]
   ,  button [  onClick Increment  ] [   text “+”  ]
           

2.5 實際效果

函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體
函數式程式設計中的戰鬥機(二) --運用elm語言MUV設計模式做一個簡單的應用執行個體1 elm語言設計模式的特點2 MVU模式實作一個滑鼠點選計數器執行個體

如此,簡單的幾行代碼,便把一個單頁面應用給寫出來了,不用html和javascrtipt混搭,而且高效、簡潔、純淨。更重要的是,在寫代碼的過程中,我們自然而然地按照模型定義、更新引擎、生成界面三個架構開展,先聲明再細節,讓自己的思維有迹可循,邏輯清晰,這就是函數式程式設計的“MUV”模式。