Ur語言

Ur也叫作Ur/Web，是一個自由和開源的函數式程式語言，專門用於web開發，由Adam Chlipala在麻省理工學院創建，它從一個單一的程序產生伺服器代碼、web瀏覽器客戶端代碼、和特定於選擇的資料庫後端的SQL代碼。

## 概述

Ur的語法基於了Standard ML，然而語言也包括來自Haskell的概念，具有額外的類型操縱。Ur支持一種基於行類型的強力的元編程。Ur/Web是Ur加上特殊的標準庫和用於解析和優化的關聯規則。Ur/Web編譯器還產生不使用垃圾回收的非常高效的目標代碼。所有這些實現都是開放原始碼的。

Ur/Web支持構造以SQL資料庫為後端的動態web應用。嵌入到語言中的SQL語法模板便利了表格處理。瀏覽器客戶端，包括了函數式反應式編程設施，使用了`(source a)`類型和`signal`單子。Ajax調用/反響，通過叫作「事務」（對應於Haskell的IO）的單子來序列化，並且它的集結和解碼被封裝在rpc函數中。

標準庫的簽名（signature），使得有良好類型的Ur/Web程序，在非常寬廣的意義上不會出錯。不只是在特定頁面生成期間不崩潰，它們還能夠做到：

- 不遭受任何種類的代碼注入攻擊。
- 不返回無效的HTML。
- 不包含應用內部死連結。
- 在HTML表單和它們的處理器所預期的欄位之間，沒有不匹配。
- 不包括對遠程web伺服器提供的Ajax風格服務有不正確假定的客戶端代碼。
- 不嘗試無效的SQL查詢。
- 在web瀏覽器和web服務之間或與SQL資料庫的通信中，不使用不正確的集結（marshaling）或解散（unmarshaling）。

這種類型安全正是Ur/Web方法論的基礎。還有可能使用元編程，通過分析類型結構來建造重要的應用部件。

## 例子程序

下面是展示客戶端、伺服器和資料庫採用Ajax通信的演示程序，來自web demos，有著勾畫每個構件的額外注釋：

接口文件（類似ML的簽名）具有`.urs`擴展名：

```sml
(* 环境单子叫做transaction，对应于Haskell的IO单子 *)
val main : unit -> transaction page
```

實現文件（`.ur`擴展名）：

```sml
datatype list t = Nil | Cons of t * list t

table t : { Id : int, A : string }
  PRIMARY KEY Id

(* 服务器端数据库访问，通过AJAX XmlHttpRequest调用。
                    封装为rpc函数(远程过程调用) *)
fun add id s =
    (* sql dml模板，据有表达式{[expression]} *)
    dml (INSERT INTO t (Id, A) VALUES ({[id]}, {[s]}))

fun del id =
    dml (DELETE FROM t WHERE t.Id = {[id]})

fun lookup id =
    (* haskell风格单子代码 *)
    ro <- oneOrNoRows (SELECT t.A FROM t WHERE t.Id = {[id]});
    case ro of
        None => return None           (* return是单子提升函数 *)
      | Some r => return (Some r.T.A)

(* check由客户端onClick事件处理器调用。
               所以它将被编译成JavaScript，成为嵌入了客户端脚本的页面 *)
fun check ls =
    case ls of
        Nil => return ()
      | Cons (id, ls') =>
            ao <- rpc (lookup id);      (* Ajax调用至服务器端 *)
            alert (case ao of
                   None => "Nada"
                 | Some a => a
                 );
            check ls'

fun main () =
    idAdd <- source "";
    aAdd <- source "";

    idDel <- source "";

    (* 生成包含有JavaScript的web页面 *)
    return <xml><body>
      <button value="Check values of 1, 2, and 3"
              onclick={fn _ => let val mylist = 1 :: 2 :: 3 :: []
                               in
                                  check mylist
                               end
                               }/><br/>
      <br/>
      <button value="Add"
              onclick={fn _ => id <- get idAdd;
                               a <- get aAdd;
                               rpc (add (readError id) a)  (* Ajax调用到服务器端 *)
                               }/>
      <ctextbox source={idAdd}/>
      <ctextbox source={aAdd}/><br/>
      <br/>
      <button value="Delete"
              onclick={fn _ => id <- get idDel;
                               rpc (del (readError id))    (* Ajax调用到服务器端 *)
                               }/>
      <ctextbox source={idDel}/>
    </body></xml>
```

項目文件（`.urp`擴展名），必須包含可選的指令（directive）列表，跟隨著項目模塊的列表：

```shell
 # hash号前缀于行注释
 rewrite url Module1/main        # 设置根URL至Module1/main函数
 exe myexename
 database dbname=test            # 数据库特性和参数
 sql noisy.sql

 $/list     # stdlib模块前缀着"$/"
 module2    # 如果被module1所用则必须前导于它
 module1    # main模块
```

- 伺服器端，沒有副作用的檢索函數的頁面（HTTP`GET`方法），經由一個URL而可訪問為`/ModulePath/functionName`，它們應當具有類型`(unit -> transaction page)`。
- 要導出可能導致副作用的一個頁面，只能通過HTTP`POST`方法來訪問，包括指定頁面處理器的一個實際參數，它具有類型`Basis.postBody`。

編譯：

```bash
 urweb module1   # 查找module1.urp
```

作為一個web伺服器來執行（其他模態有CGI、FastCGI等等）：

```bash
 ./module1.exe -p 8081   # -h : RTS选项帮助
```

## 外部連結

- Ur language home page
- Ur/Web project page on GitHub
- Ur wiki

## 基本資料

- 頭銜：Ur
- 日語原文：Ur, Ur/Web
- 語言家族：ML
- 發行日期：2014年
- 設計者：Adam Chlipala
- 軟體版本週期：20200209
- 軟體版本週期：2020年2月9日
- 受影響於：ML, Haskell
- 平台：POSIX
- 許可證：三條款BSD許可證
- 編程范型：函數式, 反應式
- 文件擴展名：.ur, .urs, .urp