2018 年 11 月

第 33 卷,第 11 期

.NET-使用符號的委派建立您自己的指令碼語言

藉由Thomas Hansen |2018 年 11 月

我喜歡我C#編譯器。我女友宣告我最喜歡,多個我喜愛她,,雖然原因很明顯,我會永遠不會承認該中公開。強型別、 泛型、 LINQ、 記憶體回收,CLI,各項特性的不只如此。不過,既然我需要幾天關閉從與我編譯器通常會提供我習慣證券。對於這天內,我選擇動態程式設計語言的程式碼 — 和越動態語言,更危險又有趣。

好的。足夠的簡介。現在讓我們進行哪些真實的程式設計人員執行單,讓我們建立的程式碼:

hello world

什麼?您以為我說過 「 程式碼 」?Yup,我當然沒有,該文字實際上是程式碼。若要了解,我們來看看您可以此程式碼。看看**[圖 1**,其中顯示的項目我稱它為符號的委派簡約的範例。建立空白的主控台應用程式在 Visual Studio 和從程式碼中的型別**[圖 1**。

[圖 1] 的符號委派簡約的範例

using System;
using System.Collections.Generic;
class MainClass
{
  public static void Main(string[] args)
  {
    // The "programming language"
    var keywords = new Dictionary<string, Action> {
      // The "hello" keyword
      ["hello"] = () => {
        Console.WriteLine("hello was invoked");
      },
      // The "world" keyword
      ["world"] = () => {
        Console.Write("world was invoked");
      }
    };
    // The "code"
    string code = "hello world";
    // "Tokenising" the code
    var tokens = code.Split(' ');
    // Evaluating the tokens
    foreach (var token in tokens) {
      keywords[token]();
    }
  }
}

只要 25 行程式碼中,我已經建立我自己 micro 的程式設計語言。若要了解它的優點,了解 「 程式碼 」 變數,可以傳送透過網路;它可以擷取從資料庫中;它可以儲存在檔案中;我可以和動態變更的字串"hello world"到"world hello,"或"hello hello world world",就此而言,完全變更它所評估的結果。這項功能表示我可以動態地組合以得到一份函式物件,依序評估,根據程式碼的內容的委派。突然我已轉換成動態的指令碼語言的靜態編譯的程式語言,只要將句子分割成其文字,然後使用個別的單字作為查閱索引鍵,為字典。中的字典**[圖 1**,因此,會變成 「 程式設計語言 」。 實際上,它是一個符號的委派。

這個範例是很明顯地不有趣,並只為了說明核心的構想。我要建立更有趣的項目追查兔子漏洞中,這些想法有點進一步所示**[圖 2**。

[圖 2 動態鏈結委派

using System;
using System.Linq;
using System.Collections.Generic;
public class Chain<T> : List<Func<T, T>>
{
  public T Evaluate(T input)
  {
    foreach (var ix in this)
    {
      input = ix(input);
    }
    return input;
  }
}
class MainClass
{
  public static void Main(string[] args)
  {
    var keywords = new Dictionary<string, Func<string, string>>
    {
      ["capitalize"] = (input) =>
      {
        return input.Replace("e", "EE");
      },
      ["replace"] = (input) =>
      {
        return input.Replace("o", "0");
      }
    };
    string code = "capitalize replace";
    var tokens = code.Split(' ');
    var chain = new Chain<string>();
    chain.AddRange(tokens.Select(ix => keywords[ix]));
    var result = chain.Evaluate("join the revolution, capitalize and replace");
    Console.WriteLine(result);
  }
}

現在看起來幾乎蠻有用的一些東西,能夠以動態方式鏈結在一起的委派,這會產生 lambda 物件中的鬆散偶合函式。因此程式碼會宣告一連串的函式,以根據我選擇放入我的程式碼的符號,循序轉換物件。在此您通常不應該繼承從清單中,但若要簡化範例,我決定這樣做來說明主要概念。

擴展這個概念很簡單。此練習後,若要尋找最小公分母可以描述您知道,這只是剛好是下列委派任何程式設計建構的泛型委派:

delegate object Function(List<object> arguments);

這個委派可代表曾發明了幾乎每個程式設計結構。運算中的所有項目可以採用輸入引數的清單,並傳回至呼叫端的某些資訊。此委派就是所有的運算意見的輸入/輸出基本的而且會成為不可部分完成的程式設計結構,您可以使用來解決您所有的運算問題。

符合 Lizzie

因為我撰寫這篇文章,我建立了 embodying 上述概念的程式語言。我撰寫了整個語言 — 我稱之為 Lizzie — 我女友探索 Lisbeth 之後 — 幾種全部投注滿月週末。語言完全包含在單一組件,大致上 2,000 幾行程式碼。編譯時,它只 45 KB 我光碟中,且其 「 編譯器 」 僅 300 行的C#程式碼。Lizzie 也很容易擴展,而且可讓任何人加入自己的 「 關鍵字 」,可讓您輕鬆地建立您自己的特定領域語言 (DSL)。這類語言的一個使用案例是以規則為基礎的引擎,您要結合在一起的程式碼動態地比C#可讓。使用 Lizzie 可以將動態指令碼新增至您以靜態方式編譯C#turing-complete 程式程式碼片段功能的應用程式。Lizzie 是C#哪些 spice 是您 dinner。您不想要只 spice 會用掉,但如果您將某些 spice 您 steak 加入時,您的經驗很明顯地變得享有更暢快。若要試用 Lizzie 出,建立空白的主控台應用程式中C#、 以 NuGet 套件,新增 Lizzie 和使用中的程式碼圖 3

[圖 3 建立特定領域語言

using System;
using lizzie;
class Demo1
{
  [Bind(Name = "write")]
  object write(Binder<Demo1> binder, Arguments arguments)
  {
    Console.WriteLine(arguments.Get(0));
    return null;
  }
}
class MainClass
{
  public static void Main(string[] args)
  {
    var code = "write('Hello World')";
    var lambda = LambdaCompiler.Compile(new Demo1(), code);
    lambda();
  }
}

只是 22 行程式碼我已說是建立我自己的 DSL,並加入自己的網域特定關鍵字的語言。

Lizzie 的主要功能是,您可以繫結您 Lizzie 的程式碼的內容型別。中的 LambdaCompiler.Compile 方法**[圖 3**事實上是,由第一個引數的泛型方法,但其類型引數會自動推斷。就內部而言,Lizzie 會建立繫結至您的型別,以繫結屬性的所有方法讓您都能夠從您的 Lizzie 程式碼的繫結器。評估您的 Lizzie 程式碼時,它會有一個額外的關鍵字,稱為 「 寫入 」。 您可以繫結的任何方法 Lizzie 的程式碼,只要它具有正確的簽章。此外,您可以將您 Lizzie 程式碼繫結至任何類型。

Lizzie 有數個預設關鍵字,它讓您針對自己的程式碼,但您不需要使用這些,如果您不想要。[圖 4示範更完整的範例,會使用這些關鍵字的部分。

[圖 4 使用某些預設關鍵字

using System;
using lizzie;
class Demo1
{
  [Bind(Name = "write")]
  object write(Binder<Demo1> binder, Arguments arguments)
  {
    Console.WriteLine(arguments.Get(0));
    return null;
  }
}
class MainClass
{
  public static void Main(string[] args)
  {
    var code = @"
// Creating a function
var(@my-function, function({
  +('The answer is ', +(input1, input2))
}, @input1, @input2))
// Evaluating the function
var(@result, my-function(21,2))
// Writing out the result on the console
write(result)
";
    var lambda = LambdaCompiler.Compile(new Demo1(), code);
    lambda();
  }
}

中的 Lizzie 程式碼**[圖 4**首先會建立稱為 「 我函式,"的函式,則它會叫用該函式使用兩個整數引數。最後,它會寫出到主控台的函式引動過程的結果。21 行的C#程式碼和八個 Lizzie 程式碼行,我已評估一段以動態的指令碼語言,從建立函式的動態程式碼我C#程式碼,我使用的指令碼語言中加入新的關鍵字。花費 33 只要幾行程式碼的總計,包括註解。這 33 行程式碼可讓您宣告已建立自己的程式設計語言。Anders Hejlsberg、 移 rover,並讓小 Jimmy 接管...

是 Lizzie 「 真實 」 的程式設計語言?

若要回答這個問題,您需要思考您考慮要實際程式語言。Lizzie 是 turing-complete 程式,並至少在理論上,可讓您解決每個您可以想像得到的運算問題。因此,構成 「 真實 」 程式設計語言的正式定義,根據它是肯定和任何其他程式設計語言,真的。相反地,它具有不解譯或編譯,因為每個函式引動過程就只需字典查閱。此外,它的特色只有少數幾個建構,而且所有項目以 「 function(arguments)"語法。事實上,即使陳述式遵循先前定義的泛型委派中的函式語法:

// Creates a function taking one argument
var(@foo, function({
  // Checking the value of the argument
  if(eq(input, 'Thomas'), {
    write('Welcome home boss!')
  }, {
    write('Welcome stranger!')
  }) // End of if
}, @input)) // End of function
// Invoking the function
foo('John Doe')
The syntax of if is as follows:
if(condition, {lambda-true}, [optional] {lambda-else})

"If"關鍵字的第一個引數是一個條件。第二個引數是 lambda 區塊,會評估在條件產生非空值 (true)。第三個引數是選擇性的 lambda 區塊會評估在條件產生 null (false)。因此"if"關鍵字事實上是函式,您可以提供 lambda 引數,使用"{...程式碼...}"語法以宣告您的 lambda。因為所有項目之間的開頭和結尾括號內的關鍵字,不同於其他程式設計語言,使用更傳統的語法會進行,這可能會覺得稍微奇怪剛開始。不過,若要建立 300 的幾行程式碼的程式設計語言編譯器,一些粗體決定只需要讓進行。而 Lizzie 是簡單的所有相關資訊。

Lizzie 的函式的非常類似 s 運算式結構的從 Lisp,如此不奇怪的 Polish notation 需要。因為 s 運算式可以描述任何項目,而且 Lizzie 的函式只是 s-運算式使用的符號 (第一個引數) 外它的括號中,您可以描述 Lizzie 與任何項目。這可以說變成 Lizzie Lisp 的 Common Language Runtime (CLR),以更直覺的語法的動態實作C#/JavaScript 開發人員。它可讓您將在您以靜態方式編譯之上的動態程式碼C#,而不需要讀取數千個頁面的文件,以了解新程式設計語言。事實上,Lizzie 的整個文件只是文字的 12 頁,這表示軟體開發人員可以解譯為常值了 Lizzie 在 20 分鐘的時間。

Lizzie — JSON 程式碼

Lizzie 我最喜歡的功能之一是它缺乏的功能。讓我舉這 Lizzie 無法執行的部分清單。Lizzie 無法:

  • 從您的檔案系統讀取或寫入
  • 執行 SQL 查詢
  • 要求您提供您的密碼
  • 完全變更電腦的狀態

事實上,您不能惡意,甚至在理論上一段 Lizzie 現成的程式碼 !這缺少的功能可讓 Lizzie 一些獨特的功能,Roslyn 和C#指令碼不會提供。

在其原始狀態,Lizzie 是完全安全,可讓您安全地傳輸程式碼在網路上從一部電腦,另一部電腦,您會使用 JSON 來傳輸資料的相同方式。然後在您接受 Lizzie 的程式碼的端點,您必須明確地實作任何函式需要您 Lizzie 的程式碼存取,以便讓它適用於您的使用案例的支援。這可能包括C#從 SQL database 或的能力,來更新 SQL database 中的資料,或讀取或寫入檔案中讀取資料的方法。不過,所有這些函式引動過程可以延遲到您已確認,嘗試執行任何它正在嘗試執行的程式碼實際上允許這麼做。因此,您可以輕鬆地實作驗證和授權之前允許它,例如"insert sql,"[讀取的檔案] 或任何其他項目。

Lizzie 的這個屬性可讓您建立泛型 HTTP REST 端點,用戶端層傳送 Lizzie 程式碼到您的伺服器,然後評估的位置。此外,您就可以讓您建立 JSON 回應,它會傳送回到您的用戶端的伺服器。以及更有趣的是,您可以實作此安全。您可以實作接受只包含 Lizzie 程式碼,POST 要求的單一 HTTP REST 端點,並解譯為常值取代的 100%動態和泛型 Lizzie 評估工具為您整個的後端。這可讓您移動您的整個商務邏輯和資料存取層到前端的程式碼,使前端程式碼以動態方式建立 Lizzie 程式碼,它會傳輸給伺服器進行評估。您可以安全地假設您驗證和授權您的用戶端,才能讓它們來評估您的 Lizzie 程式碼。

基本上,整個應用程式,突然之間,輕鬆地建置以 JavaScript 或 TypeScript 或 ObjectiveC 或其他項目,而且您可以建置用戶端中,以動態方式讓任何程式設計語言建立 Lizzie 程式碼,並將此程式碼傳送至您的伺服器。

從愛因斯坦課程

當 Albert Einstein 記下他著名的方程式,以說明我們的新世界時,它必須只有三個簡單的元件: 能源、 大型和光線速度的平方。方程式可能輕鬆地了解任何舊的數學運算掌握到適當的 14 年。了解電腦程式設計,相反地,需要數千個頁面和數以百萬計如果不是數以兆計的字首字母縮略字,以及符號,再加上整個維基百科一節的範例中,許多設計模式和的語言,每個使用完全不同的結構和想法,全部都需要 「 重要 」 的架構和程式庫,您需要將您 「 解決方案 」,才能在您網域的問題開始工作。您應該知道所有這些技術的核心才能開始身為中繼軟體開發人員參考自己。我唯一一個人會看到此處的問題嗎?

Lizzie 不仙丹妙藥及兩者皆非符號的委派,但它們絕對"20 移至 10。 」 的方向中的步驟 此外,某些情況下,若要繼續時,您必須先來看一個步驟上一步。有時候您需要 neutrally 觀察自行從外部。如果,為專業人員的社群,如此一來,我們只是可能知道,我們目前 madness 問題的簡單起見和不 50 多個設計模式,15 的新查詢語言、 100 的新語言功能,和一百萬個新的程式庫和架構,每個兆個移動組件。

較不為的詳細資訊,一律,因此讓我更多更少,並降低更多 !如果您想要較少,加入我github.com/polterguy/lizzie。這是您可以在其中找到零個型別安全、 與任何關鍵字,任何運算子,沒有 OOP,絕對不太一樣 Lizzie,單一程式庫或架構深入解析。

總結

大部分的運算產業往往不同意與大部分的我的想法。如果您要求的平均軟體架構設計人員他對這些概念的思考,他會可能會擲回中臉部的整個程式庫做為來源,以證明我是如何錯誤。比方說,軟體開發的普遍假設是強型別是很好,和弱式類型不正確。對我來說,為了簡單起見其實只有遊戲現身,即使它需要擲出視窗的強型別。不過請注意的概念,例如 Lizzie 的用意在於 「 活躍 」 註冊您現有的靜態型別C#程式碼中,不會取代它。即使您從未使用程式碼中提到的觀念這篇文章直接,了解的重要概念,可協助您在傳統的程式設計語言中寫入標準的程式碼更有效率,並協助您處理其目標是為了簡單起見。

程式設計歷史教訓

上一步時資歷較淺的開發人員,我會用來建立 3 層式架構應用程式。此構想是要將資料層,從商務邏輯層和 UI 層。問題在於,因為前端架構變得更複雜,會強制您要建立 6 層應用程式架構。首先,您要建立 3 層式伺服器端架構,則 3 層式架構的用戶端的架構。然後,算是足夠,您還需要您程式碼移植到 Java、 ObjectiveC 或任何支援所有可能的用戶端有。很抱歉冒失,但這種類型是架構的我所謂 「 insanity 導向設計 」 因為它成長至在這裡,您通常幾乎無法維護的應用程式的複雜度。單一前端 UI 變更通常會透過 15 層的架構和四個不同的程式設計語言,會傳播,而且會強迫您在各層只是為了將簡單的資料行加入至前端中的資料方格中進行變更。Lizzie 會藉由使用您的前端傳送驗證碼到您的後端,而您的後端評估,並傳回您的用戶端,以 JSON 為解決這個問題。當然,您會遺失型別安全,但代價是需要緊密整合您的應用程式的不同層,在一個位置的變更傳播至您的專案中的其他所有圖層類型安全時,型別安全的成本不只是值得。

我開始撰寫程式碼時 8 歲了,在 1982年 Oric 1。顯然,我還記得我所撰寫的第一個電腦程式。它發生像這樣:

10 PRINT "THOMAS IS COOL"
20 GOTO 10

如果 8 歲小孩現在想要重現該體驗中,下列所有的最佳作法,使用用戶端的架構,例如 Angular 和後端架構,例如.NET,此 kid 可能必須知道數千個技術的電腦科學的頁面文學也是一樣的核心。相反地,我開始接觸已大約 300 頁及少數電腦雜誌的書籍。我對它頁面 100 之前,我已建立自己的電腦遊戲,年齡為 8 個。如果這讓我聽起來舊,但這不是發展及改進很抱歉,這是 「 轉移 」 和行徑。和 [是],開始 frenetically 寫下您反對的聲浪之前,此問題已科學研究,和 neutrally 觀察及確認時,所教授和 Ph.D.s,所有遠比我還要聰明。

事實是該電腦程式設計 (人類) 的職業] 在廢止的 brink 因為持續新增複雜度,可能很快就達到它已超越人類大腦的容量,以建立電腦程式的點。因為程式設計變得那麼嚴苛,從認知的觀點來看,它可能會沒有人能夠這麼 10 年之後。在此同時,讓人判讀會變得更取決於電腦和軟體每一天。撥打電話給我舊打造好,但我起來,有人浩是能夠了解的事項很重要,我快樂、 存在以及生活品質的概念。


Thomas Hansen具有已建立軟體,因為他是 8 歲了,他開始撰寫程式碼中: 1982年使用 Oric-1 的電腦。他將自己稱為 Zen 電腦程式設計師能夠設法要減少現代程式設計的複雜度,並拒絕吶任何的技術 dogmas 的信念。Hansen 適用於 Bright 賽浦路斯,他會建立金融科技軟體中的程式碼。

感謝下列 Microsoft 技術專家來檢閱這篇文章:James McCaffrey


MSDN Magazine 論壇中的這篇文章的討論