why elmlang:最簡最安全的full ola stack的終身webappdev語言選型

Minlearn發表於2020-12-12

本文關鍵字:react,stdlib inside lang,前端開發的幾種技術方向和潮流,elm editor vs vscode+elmplugin,haskell vs elmlang,
打造類tcent cloudbase的碎片化cloudapp 雲原生devdeploy環境和私有小程式平臺,把vscode當成dsl trigger editor生成器可配核心,一種可調除錯難度與核心裁剪的專業語言與ide。使用elm lang as vistual trigger lang:Time Traveling Debugger,適合webdev的函式式語言或函式式命令式混合語言,elmlang vs py,vs js

我們知道,站在最高層來看,開發是一種綜合考慮“語言,問題,人和設計”的工程行為,而軟體作為產出,是一種抽象app棧架構,一般appstack包含有網路,IO,持久,使用者介面這些子棧堆疊而成(最後是業務邏輯),這其中ui是代表,它代表一種appmodel,如desktop appmodel使用本地圖形渲染出來的gui,web appmodel使用page ui。

------ 在開發行為中,語言處在中心方案域位置(問題,設計是方案,人,語言是實現域),,而在開發中方案域和目標域的重要特徵是它們都會發生變化(軟體整個銀彈討論都是關於維護軟體生命期變動的討論),語言也處在最易變動的中心位置,本身作為變化體串聯起這種變化:比如,一般情況下,我們都是用通用語言+庫擴充套件來解決問題的,侷限於使用語言本身提供的對映手段來解決新出現的問題,但當語言本身的抽象手段不夠用時,我們往往將其DSL化:提出一種新語言或對現存語言綜合增強改造,這種語言多變適配開發可以任意方向發展,往往一個價值觀,一個硬體特性,對方案和實現領的任何鉅細修補行為,都可以成為主導發明一種新語言特性的理由,,不信去看網上的一份《Every Language Fixes Something》and only something,

------ 包括語言在內,我們可以把處理“語言技法問題,抽象問題,對映人的設計需求”這些綜合問題在內的開發體做成中介軟體appframework,它屬於解決問題的“一次大而全的設計和實現”,一般封裝直到建立appstack為止(給開發者最大關注業務邏輯的時間而不是浪費在appstack本身上),比如qt就是一種框架(qt為cpp增加了moc和event,signal,和gui框架,已經把app變成了qtcpp,因為給cpp增加庫級已經不能不能滿足qt的需求,所以它乾脆改造工具鏈加入moc處理,對應上面提到的“這是一種對問題人語言的綜合處理反映到語言層的處理”,一般框架具體到產生一個APP結構兼實現業邏輯的功能。,qt的庫包含了對桌面APP的實現,一起組成了整個qt框架),而高階的框架它超越語言和應用stack,甚至考慮到對OS改造。全程提供full ola(os,langsys,appstack) stack增強或改造,如plan9。(後者叫架構更合適)。

這其中,appstack,appmodel,applang,appframework都是有機聯絡的,定義APP的UI,即appstack中的ui部分尤為重要,如果說appstack決定一種APP型別,往往也決定開發APP選用的這門語言的選型和框架架構結構,拿上面的qtcpp桌面開發來說,物件導向+訊息往往是QTcpp這種語言的ui方案,desktop ui天然就是一個widget元件樹存在互動和管理這些互動的元件,這類OO語言如java能很好handle,,事情到了web前端領域,作為最能體現程式設計技術潮流的前沿地方,框架和語言的變化在這裡變動更劇烈,也存在著關於UI開發延伸到語言的變化的類似程式:html頁面不是desktop gui那套,而是一種js api視角的dom,js有部分函式特性函式是一級物件,functional特性的js本身能很好處理這種dom,OO反而不必(正如在函式語言中一等函式型別可以輕易表達很多設計模式問題一樣,傳統的OO命令式語言需要藉助介面這類複雜的東西來達成),最初的人們滿足於簡單的js+html,然後,需求更新了:後來人們想得到更強大的js前端頁面,提出了jquery.js擴充套件操作dom,實現了在一次bs互動中動態更新某節點的功能,這僅僅是往js語言擴充套件了一個庫。到後來,他們想得到universal desktop and mobile/webapp(非universal platform app,非蘋果釋出了m1晶片和新的arm macbook和big sur 16,真正將ios做到了intel上的APP。),讓web頁面做到跟桌面GUI一樣強大,以及single page app這類東西的時候,實際上,對頁面的動態性和效能優先已經到了一個很高的地步,各種xx.js擴充套件和不斷的ecma標準化已經很難框定這類東西了,人們發現原來流行純函式式語言時代的某些語言和機制可能才是處理這種邏輯(fullwebstackdev)的最佳方式(js跟純函式式語言還是有點區別),比如函式語言的FRP可以適配更多 dom ui方面的新需求:因而越來越多的框架應運而生,angular,react ,vue 三大開源框架,他們最大限度解決了前端 頁面載入速度 及更新速度問題(稍後會談到使用virtualdom和diff演算法)。當然,也方便書寫和開發。於是,當前端可以以統一的frp react方式被解決時,這種手段也被包含在後端形成mvc,形成full webstack級的框架方案。

純函式語言與ml系函式語言:
我們知道,馮氏機程式碼的眼中只有指令和資料,這二者是平等的東西,存在時空可置換原則,馮氏機中的程式語言也有二派。一種是命令式,一種是宣告式,函式語言一般屬宣告式語言,前者主要針對程式碼中的資料作資料方向的創新抽象,並整合到語言,後者主要是函式式主言這類針對程式碼結構進行語言發明創新方向的成就
同樣的道理髮生在軟體抽象的任何地方正如指令碼和資料一個是時間一個是空間,你可以用指令碼編碼資料本身,也可以把指令碼作為資料檔案供呼叫,,(還比如devops把部署自動化了,也是命令指令碼化了,資原始檔化了,這樣就為開發上雲準備了條件(因為做成了可被呼叫的“程式碼”形式在雲上的異地容器執行完成,我們終端只需獲得結果),再加上雲ide我們就徹底不需要在本地維持一個開發環境。)
純函式語言,偏函式,高階函式是函式語言的語言級區別於命令式的概念,純函式的特點是:無狀態,無副作用,無關時序,冪等(無論呼叫多少次,結果相同),這些數學上的東西可以實踐成函式語言,但完美表達數學概念的語言機制實際上作為實用工具來使用會顯得很原始,這種語言穩健,精美的型別系統能自由安全處理,推導資料型別的正確性和安全性(不過這樣也有drawback,函式呼叫深度debug比較麻煩列印出中間結果比較費勁)。寫的時候能調通的程式碼基本沒什麼bug,自帶併發你完全不用考慮那些諸如死鎖,執行緒池等等的複雜概念,天然適合分散式和容錯系統,但學習成本和適用範圍比命令式語言要高很多(像Monads和Functors這樣的東西很難理解,特別是沒有數學背景),還有比如它的程式碼中不帶資料和變數(傳數也不便,monads用管道類似的操作來傳數),沒有迴圈,只能用作為超集的遞迴代替。而我們現在使用的命令式則走的是另一個相反的反面,比較親和大眾但是副作用和學習曲線也相當巨大,併發需要涉及到加解鎖。
命令式這就是我們現在正在流行的C系派生出來的大支,而函式式語言曾經在學術界非常流行,近幾年也有一些流行但都偏小眾。如一些年前曾經流行的erlang也被選為最不推薦學習的語言之一
因此,現在的函式式語言,大部分是混合命令式和函式式,在純函式語言中加入了一些命令式的成份來稀釋它使它變得實用,同時保留函式式語言的大部分優點。保留了函式式針對程式碼結構而不是資料化方向創新的成果,使得函式語言中的函式變成傳統過程式(子過程函式)的合理延伸,,比如haskell和Ocaml就是這樣一種ml思想(基於ml 1975年metalanguage的派生)而elmlang就是haskell的子集。

在前面《elmlang:一種編碼和視覺化除錯支援內建的語言系統》和《在群暉docker上裝elmlang可視除錯編碼器ellie》中,我們重點講到elmlang作為函式語言用於webappdev的一些FRP原理和基礎及elmlang的visual debuggable特性,本文則是從elmlang用於fullwebstackdev語言選型方面的細節和合理性角度講的,即以下幾個方面介紹elmlang:

1)。elmlang是一種基於ml系的haskell派生的語言。本身是用正確的語言幹正確的事的典範,elmlang在語言期就給webapp保證的很多webapp的專用開發特性,如pure views, referential transparency, immutable data and controlled side effects,所以在擴充套件級和使用者級可以做很少工作就可以寫出webapp。注:除了這些,elmlang還提供執行期無錯和time可回溯的debug(這些都來自於母體haskell的函式語言特性)。

2)。elmlang是封裝了從applang到appframework一條龍的東西。elmlang的核心和標準庫包括了開發webapp的必要成份,elmlang現在整體庫的體量達到了1.5k。一切都是all at hand,但elm與py這類batteryincluded不同,因為elm不定位於通用語言,所以它是webdev的終身語言。注:elmlang app本身卻沒有提出一個appstack的web框架之類的東西,它推薦使用elixer+phoinex。ellie正是使用的這一架構。

下面詳細解析:

elmlang:用正確的語言幹正確的事。webdev = elmlang as functional programming language,vs python,vs rust

我們這裡在討論作為方案的語言對應於解決問題的問題域的手段,要知道,語言能完成的事情都一樣,因為它們都是圖靈完備的,但成本和抽象手段都不一樣,人們顯然更追求用最簡單的語言能提供的最直接的對映手段去表達一個問題的解決:

這種簡便性體現之一是程式碼可以寫得更少更直觀更符合自然語言:比如py的成功,它用字母代替一些邏輯符合,它用很多語法糖generator造出很多方便的寫法。這樣下來,一個.py檔案顯得很清爽,甚至一個沒有寫過程式的新手,都能在他的意念裡推匯出這些程式碼的用意(前提是它熟悉一些C過程式的東西),這是提高語言流行度一個最得分的選項(保證更少的程式碼是一個重要方面,或者說,python可以用其它語言的經驗來“推導”出其靈活的用法。這種靈活正是為了能在python中少寫程式碼,使程式碼顯得簡單。主要集在中語句和寫法上的創新上。python是一門從核心創新的語言(集中在過程式和單條語句上)。而不是像其它語言一樣從外部和範型級別增加新東西擴充功能去創新。)當然,其實py本身是很複雜度的,python的簡單是上帝視角下比較了多門語言的不便之後,發現了py其實是一門靈活膠水特性之後的認知開始的(棄它的缺陷不顧,如全域性gil,無jit慢)新手學py,還是一樣難的(甚至py越是靈活就越顯蒙逼)。而且它作為膠水是batteryfullincluded不像lua只配了一個語言核心。。Guido開發Python的初衷:開發者需要一種高階指令碼語言,在易用性和功能性之間取得平衡、在處理複雜邏輯時沒有Unix shell的限制;能夠像C語言那樣,全面呼叫計算機的功能介面,又可以像shell那樣,可以輕鬆的程式設計。但是python對於shell的包容實際上沒有perl好。

elmlang它使用了haskell的子集。一開始就定位於簡化程式碼而設計,跟py的目的有異曲同工之妙,elmlang的docs中,有很多函式語言haskell的成份和章節。還有天然的Debuggable屬性:它維持了一個Predictable State Container for JS Apps
這使得it easy to trace when, where, why, and how your application’s state changed.促成"time-travel debugging", and even send complete error reports to a server.

除此之外它是安全的,它與rust語言安全型別與併發的異曲同工之處:比如error處理和pattern matching(實際上,異常和其他資料結構一樣是同質的,不是有特殊語法規則和能力的元素。因此也可以複用其他用於組合和處理資料結構的方法論和工具。elmlang執行期免錯,是因為它有函式型別的maybetype,A Maybe type may or may not contain a value, we must handle the case where the value is Nothing)。當然這種脫離語言本質區別所屬比較是沒有意義的,但它們在維持安全的外觀上是很相似的。

最後,當然還是那句話:對於沒有任何基礎的初學者來說,任何語言都一樣絕對難,只是相對不難。elmlang和py就是相對不難的。

elmlang是封裝了從applang到appframework一條龍的生態級東西。vs js

新語言直接提供了新問題所需要的元素,整合了更簡便的表達問題域的方式,即通用語言核心就整合了專用問題域方案而儘量不借用擴充套件庫來完成沒有多少其它亂七八糟的東西。“通用語言幹啥啥都行,幹啥啥幹不好”,而DSL或許才是出路(如上,這種DSL不是擴充套件一下通用語言的庫就行了,而是重新設計整個生態或再度框架化一次最優方案)

拿js來說,js的出現和選型本身就是一種DSL化,它是非同步IO語言,是web前端的良好選型,瀏覽器中的js只繫結dom,不是通用語言,後端的nodejs算是通用語言。這二種執行環境中,較其它語言js其實最本質的特點是它的IO。Ryan在發明nodejs時,他評估了很多種高階語言,發現很多語言雖然同時提供了同步IO和非同步IO,但是開發人員一旦用了同步IO,他們就再也懶得寫非同步IO了,所以,最終,Ryan瞄向了JavaScript。因為JavaScript是單執行緒執行,根本不能進行同步IO操作,所以,JavaScript的這一“缺陷”導致了它只能使用非同步IO。(注:不要把非同步IO與併發弄混,在單核語言的前提下和限制下,實現併發。用盡單核語言的潛能。JavaScript是單執行緒執行的,不存在後臺語言那種併發執行。一些程式語言/環境只有一個執行緒。這時如果需要併發,協程是唯一的選擇。)

對於elmlang,如果說js是一種focusing io的子集做進語言核心,那麼elm進一步focusing on frp and react patten,elm對前端開發的支援和融入到語言本身是原生植入到語言的。elm架構和生態在js擴充套件端的對應物是redux全家桶。 redux參照了elm架構,而不是反過來。二者共享很多相同的成份和實現。

Elm is reactive. Everything in Elm flows through signals. A signal in Elm carries messages over time. For example clicking on a button would send a message over a signal.
You can think of signals to be similar to events in JavaScript, but unlike events, signals are first class citizens in Elm that can be passed around, transformed, filtered and combined.

下面簡單梳理下React 的工作原理及虛擬dom 和 diff演算法

與 jq等不同,React 會建立一個虛擬 DOM(virtual DOM)。虛擬dom 說白了 就是真實dom樹的一個描述,用js的物件去表示真實dom ,當一個元件中的狀態改變時,React 首先會通過 “diffing” 演算法來標記虛擬 DOM 中的改變,第二步是調節(reconciliation),會用 diff 的結果來更新 DOM。所有顯示模型資料的 Views 會接收到該事件的通知,繼而檢視重新渲染。 你無需查詢DOM來搜尋指定id的元素去手動更新HTML。 — 當模型改變了,檢視便會自動變化。------ 這又是一個解放程式設計師雙手讓他們關注業務邏輯的框架帶來的功勞
將Virtual DOM(虛擬Dom)樹轉換成Actual DOM(真實Dom)樹的最少操作的過程,叫作調和。diff演算法是調和的具體實現,將O(n^3)複雜度 轉化為 O(n)複雜度。diff演算法原則:分層同級比較,不跨層比較;相同的元件生成的DOM結構類似;組內的同級節點通過唯一的id進行區分(key)
整個框架級別,通過Models進行key-value繫結及custom事件處理,通過Collections提供一套豐富的API用於列舉功能,通過Views來進行事件處理及與現有的Application通過RESTful JSON介面進行互動.


無論如何,elmlang可作為你的終身語言如果你是一個webdever。再也不要去追逐一門通用語言並寄希望於擴充套件它的庫能達到終身適用其它未知未來領域了,因為這好似不可能。all inside,all at hand,

elmlang這種語言因為面向一種業務領域。很容易積累起知識群,經驗群等社群。面向search engine也是一種,雖然它要搜尋一次。也算某種面向搜尋引擎程式設計。面向XX也罷,因為一切all at hand,searchable,左右逢源,無論什麼問題都有參考能獨立解決,總是最好的學習,,

未來我們進一步縮小這個webapp的範圍將elmlang打造成webapp trigger editor and cloud app editor環境和workshop.

相關文章