微软推出新逆天开源语言Bosque,告别 for 循环,提高开发效率!
擁抱開源的微軟近日又為開發者帶來好消息:在受 TypeScript 語法類型與 ML 和 Node/JavaScript 語義啟發下,微軟推出了全新的開源編程語言 Bosque。
Bosque?創作者是微軟研究院的計算機科學家 Mark Marron,他設計通過擁抱代數運算和避開導致復雜性的技術,試圖創造出一種簡單易懂的語言,走出 1970 年代興起的結構化編程模型。如今,Bosque 似乎已經實現了這一點,它不再需要“for”、“while”、“do while”等循環,可讓開發者開發效率更高。
與此同時,本文的作者 Erik Pragt 也發現?Bosque 和 Kotlin 有著諸多的相似之處。
作者 |?Erik Pragt
譯者 | 彎月
責編 | 屠敏
出品 | CSDN(ID:CSDNnews)
以下為譯文:
昨天,我的一個同事Sahil發給我一個鏈接,鏈接的文章介紹了微軟研究院發布的新語言Bosque。在讀了這篇文章,看了里面的代碼示例后,我不禁想看看它和Kotlin有多少相似之處。我想通過這篇文章,分享我使用Bosque語言的短暫經驗,以及它和Kotlin的比較。我不會深入討論Kotlin和Bosque的生態系統,這篇文章的重點是語言結構和語法本身。
什么是Bosque編程語言?
?
Bosque是微軟研究院發明的一門新的編程語言。在我撰寫本文的時候,Bosque語言才剛滿11天!根據Bosque的GitHub頁面(https://github.com/Microsoft/BosqueLanguage),Bosque的設計目標是“編寫簡單、明確且人和機器都容易理解的代碼”。因此,Bosque吸取了許多概念,例如不可更改性、原子構造器、工廠等,還有豐富的類型系統。
Bosque是一門非常新的的語言,它的語法受到了TypeScript的啟發。從我的另一篇文章《Kotlin vs TypeScript》(https://www.jworks.io/dart-vs-typescript-vs-kotlin-js/)中,你就可以看出兩者之間有許多相似之處,因此不難想象,Kotlin和Bosque之間也會有許多共同點。
?
Bosque vs Kotlin:語法
?
Bosque的GitHub頁面上給出了一小段Bosque代碼示例,這段代碼很好地展示了它與Kotlin之間的相似性:
//?Bosque?
function?add2(x:?Int,?y:?Int):?Int?{
????return?x?+?y;
}
add2(2,?3)?//5
//?Kotlin
fun?add2(x:?Int,?y:?Int):?Int?{
????return?x?+?y;
}
add2(2,?3)?//5
盡管這段代碼非常簡單,但應當注意到,Bosque的語法與非常規版本的Kotlin非常相似。唯一的區別就是關鍵字function與fun的不同,其他代碼完全一樣。我們來看看更多的示例。
Bosque網站上給出了一個簡單的井字棋游戲(https://github.com/Microsoft/BosqueLanguage/blob/master/docs/tictactoe.md)。雖然我完全沒有編寫Bosque代碼的經驗,但這段代碼非常直觀,除了一些像'x'#PlayerMark;(有類型的字符串)、@[ 2, 2 ](元組/結構)和this<~(cells=this.cells..(原子批量數據操作)等語法糖之外。
下表總結了Bosque的井字棋游戲游戲示例中用到的一些語言概念,以及對應的Kotlin概念。這個列表并不完整,但可以讓你方便地理解兩種語言的代碼示例:
| 語言特性 | Bosque | Kotlin |
| 不可更改的值(Immutable Values) | 全部 | 部分(基本類型,集合) |
| 有類型的字符串(Typed Strings) | 支持 | 內嵌類或類型別名 |
| 靈活調用(Flexible invocations) | 命名實參 | 命名實參 |
| 批量代數數據操作(Bulk Algebraic Data Operations) | x<~(f=-1, g=-2) | copy()方法 |
| 短路運算符(o?.m) | 使用問號 | 使用問號 |
| 原子構造器(Atomic Constructors) | 支持 | 伴生對象(Companion Objects) |
| 元組(Tuples) | 支持 | 不支持(僅支持Pair/Triple) |
| 函數類型(Function types) | 支持 | 支持 |
?
現在我們對兩門語言有了一點理解,接下來我們再來深入看一看井字棋游戲的代碼,看看兩者具體的比較情況。如果你想直接看結果可以點這里(https://gist.github.com/bodiam/749b5174d26522cdaeba43c1401cbc8d)。如果你有耐心看下去,我可以帶你閱讀一些代碼,并給出相應的Kotlin代碼。
?
Bosque井字棋
?
井字棋的示例是一個小游戲,玩家可以明確指定走哪一步,也可以隨機走一步。游戲不需要修改狀態,因為一切都是不可修改的。
Bosque有類型字符串
在井字棋示例中我們看到的第一個語言概念就是有類型字符串(Typed Strings):
const?playerX:?String[PlayerMark]?=?'x'#PlayerMark;
const?playerO:?String[PlayerMark]?=?'o'#PlayerMark;
上面這段代碼創建了兩個常量:playerX和playerO,都是有類型的字符串。也就是說,PlayerMark類型的字符串不能與包含郵政編碼的字符串兼容。
Kotlin不支持有類型字符串,但提供了內嵌類(Inline Class)或類型別名(Type Aliases),可以用在類似的場合。內嵌類可能更好(我們稍后會講到),但現在先來看看類型別名。類型別名促使Kotlin代碼更接近Bosque代碼:
const?val?playerX:?PlayerMark?=?"x"?as?PlayerMark
const?val?playerO:?PlayerMark?=?"o"?as?PlayerMark
Bosque類型
接下來看看這段代碼:List[[Int, Int]]。可以想象這是一個列表,但列表的元素類型為結構類型[Int, Int]。因此,該列表只能包含整數對。
在Kotlin中,如果類型能夠推斷出來,我們就不需要明確定義,但如果要定義的話可以寫成List<Pair<Int, Int>>,寫法非常相似。
Bosque結構類型
如果需要保存數據,但不希望定義類,則可以使用結構(Struct)。在Bosque中,結構類似于:@[ 0, 0 ]。它定義了一個結構,包含兩個值:0和0。
雖然Scala等語言都有結構,但Kotlin從早期的某個版本開始就不再支持結構了。聽起來似乎有點奇怪,因為盡管有時候結構的存在是合理的,但是結構并不會提高代碼的可讀性,而且創建數據類也非常容易。同時,Kotlin原生支持Pair和Triple,因此在Kotlin中可以利用to方法創建上述結構:0 to 0,得到的結果是一個Pair對象。
Bosque前置條件
另一個有趣的概念是前置條件(preconditions),該功能可以通過requires關鍵字檢查函數的輸入。
requires?0?<=?x?&&?x?<?3?&&?0?<=?y?&&?y?<?3;Kotlin也有同樣的概念:
require(?0?<=?x?&&?x?<?3?&&?0?<=?y?&&?y?<?3)但是,除了支持前置條件外,Bosque還支持后置條件(postconditions)。后置條件可以檢查函數是否返回了正確的值,例如ensures _result_ % 2 == 0; 可以檢查返回值是否為偶數。
Kotlin也支持范圍檢查,因此我們可以通過重構用更加常規的形式編寫上述代碼成。
Bosque的原位更新
有一個很不錯的功能,但Kotlin中卻沒有:通過拷貝的方式更新一個不可修改的列表。在Bosque中可以用下面的代碼實現:
return?this<~(cells=this.cells->set(x?+?y?*?3,?mark));上面這段代碼創建了cells列表的拷貝,并將x + y * 3位置上的值更新成了mark。在Scala中,該操作可以通過updated方法實現,但Kotlin不支持這個方法。該方法已經有了一個YouTrack問題票,所以如果你想要這個功能,可以去為該功能投票。同時,你還可以通過創建擴展函數的方式來創建自己的updated方法:
private?fun?<E>?List<E>.updated(index:?Int,?value:?E):?List<E>?{
????return?this.toMutableList().apply?{?set(index,?value)?}
}
如果你希望編寫一段效率更高、但可讀性較差的代碼,則可以參考重構后的Kotlin版本,或參考上述YouTrack問題票。
Bosque的擴散操作符
Bosque代碼中還有一行非常有意思:
var?tup?=?opts->uniform(rnd);
nboard?=?this.board->markCellWith(...tup,?mark);
這段代碼創建了新的棋盤(nboard),該棋盤是當前棋盤的拷貝,是根據一個從列表中的數據項半隨機(uniform,表示根據種子來選取)地創建的。由于tup變量是元組,因此可以利用...操作符來擴散(spread)其內容。
盡管Kotlin也有擴散運算符,但沒這么靈活。它只能在調用vararg方法的時候使用。但是,Kotlin中只能做到使用Pair的第一個或第二個值,或者更Kotlin的方式是,像下面這樣先將Pair解構:
val?(x,?y)?=?opts.random(Random(rnd))
nboard?=?this.board.markCellWith(x,?y,?mark)
但是,由于我們希望盡可能地與原始代碼相似,所以暫時線直接使用第一個和第二個值:
nboard?=?this.board.markCellWith(tup.first,?tup.second,?mark)?
結果
?
上面的比較給出了一些Kotlin和Bosque之間的異同。作為本文的結果,我們現在有了三個不同版本的井字棋代碼:
-
原始的Bosque代碼:https://github.com/Microsoft/BosqueLanguage/blob/master/docs/tictactoe.md
-
原始的Kotlin代碼,盡可能與上述代碼相似:https://gist.github.com/bodiam/749b5174d26522cdaeba43c1401cbc8d
-
重構后的Kotlin代碼,功能與上面的代碼相同,但使用了更多的Kotlin最佳實踐:https://gist.github.com/bodiam/c98cef9da8660a06c76883326b21a2cb
Kotlin最佳實踐
最后一個版本(即重構后的Kotlin代碼)使用了一些Kotlin的最佳實踐。我不知道Bosque中是否有這些結構,也許Bosque的代碼也可以改進。我們可以通過下列變更編寫更符合慣例的代碼:
使用內嵌類代替類型別名
inline?class?PlayerMark(val?value:?String)這種寫法可以給出更好的類型信息,避免在應該使用String的地方使用PlayerMark。
在require中使用范圍檢查
不要使用單獨的比較,我們應該使用范圍比較:
require(?0?<=?x?&&?x?<?3?&&?0?<=?y?&&?y?<?3)?//?both?statements
require(x?in?0..2?&&?y?in?0..2)??????????????//?do?the?same
去除類型信息
Bosque中的類型用法似乎很冗余。盡管Kotlin中也完全可以這樣做,但并不是必須的。所以,下面兩條語句是相同的:
//?this
val?allCellPositions?:?List<Pair<Int,?Int>>?=?listOf(
????0?to?0,?1?to?0,?2?to?0,
)
//?vs
val?allCellPositions?=?listOf(
????0?to?0,?1?to?0,?2?to?0,
)
去掉`this`
Bosque代碼似乎用了許多this,但在Kotlin中不需要這樣做,所以重構后的版本中去掉了this。
?
總結
?
總之,我希望在上文中我們很好地比較了兩種語言,我們也很期待Bosque語言將來的發展,而其他語言如C#、TypeScript或Kotlin能否采納這些概念呢,讓我們拭目以待吧。
總結
以上是生活随笔為你收集整理的微软推出新逆天开源语言Bosque,告别 for 循环,提高开发效率!的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 陈中华:李彦宏候选工程院院士,是全中国人
- 下一篇: 修复Chrome上的ERR_TOO_MA