Ring编程语言的声明式方法






4.67/5 (5投票s)
我们将了解 Ring 编程语言声明式方法的创新之处。
引言
当我们看到一些流行的声明式编程语言,如 QML、REBOL 和 Red 时,我们会发现使用对象的嵌套结构来描述解决方案是一种实用的方法,可以解决一些实际问题,我们可以专注于对象、属性以及这些对象如何相互关联。许多领域特定语言可以使用相同的编程范式开发,但开发领域特定编程语言需要一些时间、工具和技能才能做得正确!而且语言的局限性可能会导致未来出现问题,语言扩展可能需要高级技能。
为了解决这个问题,虽然这个问题多年前就已经解决了,但许多流行的通用编程语言提供了一些开发领域特定语言的方法。一个值得注意的现代语言是 Ruby 编程语言。Ruby 具有漂亮的语法、块和元编程等优点,使用这些特性可以开发许多领域特定语言并在实践中使用。此外,Kotlin 编程语言也在这一领域发挥了作用,并提供了很好的特性来实现这一目标。当然,许多编程语言都做到了这一点,但目前我能想到的是 Ruby 和 Kotlin。
当我设计 Ring 编程语言时,我意识到了这个问题,以及已经开发的各种成功解决方案。但是,一个可以用不同方式解决的问题,并不能阻止我们提供新的解决方案,至少在我们看来,新的解决方案在某些方面可能更有用、更好。
在本文中,我将介绍 Ring 编程语言中的创新特性,这些特性可用于使用嵌套结构开发领域特定声明式编程语言。我将展示全貌以及如何重用这些想法来开发我们需要的任何领域特定语言。
背景
如果您能查看 QML、REBOL、Ruby 和 Kotlin 中的以下示例,了解声明式代码可能是什么样子,那就太好了。这些示例已经是公开的,可以共享,我只是在这里开头使用它们,以便让您对使用嵌套结构的声明式方法中的事物有一个实际的了解。
(1) QML 示例
import QtQuick 2.9 #import from Qt 5.9
Rectangle {
id: canvas
width: 250
height: 200
color: "blue"
Image {
id: logo
source: "pics/logo.png"
anchors.centerIn: parent
x: canvas.height / 5
}
}
(2) REBOL 示例
view [text "Hello world!" button "Quit" on-action [quit]]
这种方法的优点在于我们可以了解对象之间的关系,定义带/不带名称的对象,设置对象属性,并专注于我们的描述(我们想做什么)。
当然,这种方法并不适用于所有问题,但它可以在许多有用的情况下使用。
我谈到过使用像 Ruby 这样的通用语言来做类似的事情。
(3) Ruby 代码可能看起来像这样
output = FancyMarkup.new.document do
body do
div id: "container" do
ul class: "pretty" do
li "Item 1", class: :active
li "Item 2"
end
end
end
end
或者
output = FancyMarkup.new.document {
body {
div id: "container" {
ul class: "pretty" {
li "Item 1", class: :active
li "Item 2"
}
}
}
}
所以 Ruby 的方法是使用方法、块和其漂亮的语法。
(4) Kotlin 代码可能看起来像这样
val data = mapOf(1 to "one", 2 to "two")
createHTML().table {
for ((num, string) in data) {
tr {
td { +"$num" }
td { +string }
}
}
}
使用 Ruby 或 Kotlin 等通用语言构建领域特定语言的优点是获得更强大的功能(扩展、自定义和灵活性),但这可能导致一些复杂性,或者至少语法不如纯领域特定语言那样简洁。
Using the Code
在 Ring 编程语言中,我们提供了一种创新的方法,通过嵌套结构实现声明式编程,但具有非常简洁的语法和高级别的自定义和灵活性。
Ring 编程语言中声明式方法的基本思想是:“不使用方法并传递块、匿名函数或闭包等参数。我们将在客户端|调用者端直接访问对象,但使用基于大括号而不是点运算符的更漂亮的语法,在调用者端,我们拥有更大的灵活性来访问任何对象,而无需修改其设计(类),我们可以在对象上下文中执行代码并使用该对象提供的公共方法和属性。此外,我们拥有自己的本地范围。我们获得了类似于闭包(仅在此用例中)的功能,但实现方式更快、更简单,不包括传递参数或修改方法定义。我们只需修改我们的类来定义我们将用于创建新对象并设置这些对象之间关系的方法”。
为了理解这个想法是多么有用,以及为什么它在 Ring 之前没有被使用!
你必须记住关于面向对象编程范式真正概念的重要一点。
“我曾认为对象就像生物细胞和/或网络上的独立计算机,只能通过消息进行通信”,Alan Kay 教授
由于 Ruby 和 Kotlin 都是面向对象语言,它们的设计者习惯于应用范式概念并隐藏数据(在大多数情况下),并通过方法调用在系统组件之间提供通信。因此,当他们试图基于其通用语言创建领域特定语言时,块、匿名函数或闭包便浮现在他们的脑海中。此外,将函数作为参数传递的思想更多地与函数式编程和一流函数相关,这些语言也考虑了这种范式。当然,我不是在谈论他们的思维方式,我只是在谈论我从 Ruby 和 Kotlin 实践设计中看到的东西。
Ring 语言考虑了这些范式(面向对象、函数式等),但当我们实现领域特定语言时,我们从不同的角度看待问题。
在 Ring 中,我们决定
- 默认情况下,所有属性都是
public
(这打破了安全规则:最小特权原则 - 为了灵活性)。 - 如果需要,您可以创建
private
属性和方法(为了安全)。 - 如果您有
public
属性,您仍然可以选择创建 setter 和 getter 方法(在灵活性之后实现安全)。 - 当您调用返回对象的方法时,可以使用大括号直接访问该对象。
- 你不必直接调用方法。你可以尝试访问一个属性。这将调用可能返回你可以访问的对象的 getter 方法。此方法将设置新对象与当前对象(`Parent`)之间的关系。
使用 Ring 编程语言中的这些简单规则/概念,我们可以继续创建使用嵌套结构的领域特定语言。
现在,这种领域特定语言会是什么样子?
Ring 编程语言中的示例 (1)
以下示例使用 Web 库定义的领域特定语言来创建 HTML 页面。
像 `div`、`h1`、`P` 等标签只是属性。当我们尝试访问这些属性时,将调用每个属性的 `getter()` 方法(`getdiv()`、`geth1()`、`getp()` 等)。这些方法将创建对象,将其添加到当前对象容器(`list`),然后返回对该对象的引用。使用大括号 `{ }`,我们可以访问该对象,并可以设置新的 `object` 属性并调用 `object` 方法。
load "weblib.ring"
import System.Web
func Main
BootStrapWebPage()
{
div
{
classname = :container
div
{
classname = :jumbotron
H1 { text("Bootstrap Page") }
}
div
{
classname = :row
for x = 1 to 3
div
{
classname = "col-sm-4"
H3 { html("Welcome to the Ring programming language") }
P { html("Using a scripting language is very fun!") }
}
next
}
}
}
Ring 编程语言中的示例 (2)
下一个示例来自 Ring 语言自带的 2D 游戏引擎
oGame {
title = "Stars Fighter!"
sprite
{
file = "images/menu1.jpg"
x = 0 y=0 width=800 height = 600 scaled = true animate = false
keypress = func ogame,oself,nKey {
if nkey = key_esc or nKey = GE_AC_BACK
ogame.shutdown()
but nKey = key_space
oGameState.startplay=true
ogame.shutdown=true
ok
}
mouse = func ogame,oself,nType,aMouseList {
if nType = GE_MOUSE_UP
oGameState.startplay=true
ogame.shutdown=true
ok
}
}
text {
animate = false
size = 35
file = "fonts/pirulen.ttf"
text = "Stars Fighter"
x = 10 y=50
}
text {
animate = false
size = 25
file = "fonts/pirulen.ttf"
text = "Version 1.0"
x = 80 y=100
}
text {
animate = false
size = 16
file = "fonts/pirulen.ttf"
text = "(C) 2017, Mahmoud Fayed"
x = 45 y=140
}
text {
animate = false
size = 25
file = "fonts/pirulen.ttf"
text = "Press Space to start"
x = 190 y=470
}
text {
animate = false
size = 20
file = "fonts/pirulen.ttf"
text = "Press Esc to Exit"
x = 260 y=510
}
Sound {
file = "sound/music1.wav"
}
}
要了解更多实现细节:请查看 Ring 文档的这一章
下面的例子解释了这个概念——只需阅读评论即可了解实现方式。
#=============================================================================================
# Declarative Programming using nested structures
#=============================================================================================
new Container # Create an object from the Container class
{
Point # Try to use the Point attribute, This will call getPoint()
{ # Access the new object created by getPoint() method
x=10 y=20 z=30 # Set the Object Attributes (x,y and z)
} # This will call the braceend() method
}
#=============================================================================================
# Implementation using Classes
#=============================================================================================
Class Container # Our class that will contains many objects
aObjs = [] # A list to store the new objects (for example Points)
point # An attribute
func getpoint # A method to be called when we use the Point attribute
aObjs + new Point # Create new object from the Point class, Add it to the list
return aObjs[len(aObjs)] # Return the new object
Class Point x y z # Define new class called Point
# A method to be called after accessing the object using braces
func braceend
? "3D Point" + nl + x +
nl + y + nl + z + nl
关注点
使用大括号而非点运算符访问对象,提供了一种与对象交互的不同方式,并能看到更多支持声明式编程和自然编程的技术。
在本文中,我们讨论了如何使用此功能通过嵌套结构开发领域特定语言。
在另一篇文章中,我讨论了如何将此功能用于自然语言编程。
开发者们常说“Ruby 块是该语言的杀手级功能之一!”
同样在 Ring 社区中,“Ring 括号是该语言的杀手级功能之一!”
Ring 是一种创新的编程语言,为自然语言编程和声明式编程提供了更好的支持。这种创新在于在面向对象编程和函数式编程的基础上,用新的实用技术支持这些范式。
此外,Ring 受以下编程语言影响
- Lua
- Python
- Ruby
- C
- C#
- 基础
- QML
- xBase
- Supernova
历史
Ring 是一种创新的实用通用多范式语言
- 2011 年 11 月:构思新语言的想法
- 2013 年 9 月:Ring 编程语言的设计和实现开始
- 2015 年 4 月:选定语言名称
- 2015 年 5 月:编译器实现完成
- 2015 年 9 月:文档完成
- 2016 年 1 月:Ring 1.0 发布
- 2016 年 10 月:Ring 1.1 发布
- 2017 年 1 月 25 日:Ring 1.2 发布
- 2017 年 5 月 15 日:Ring 1.3 发布
- 2017 年 6 月 29 日:Ring 1.4 发布
- 2017 年 8 月 21 日:Ring 1.5 发布
- 2017 年 11 月 30 日:Ring 1.6 发布