การเรนเดอร์th-TH

Types and values

Data types#

Faber มีระบบชนิดข้อมูลแบบสถิตที่ให้ชนิดข้อมูลมาก่อน ทุกการประกาศจะวางชนิดข้อมูลไว้ก่อนชื่อ: ข้อความ ชื่อ ไม่ใช่ ชื่อ: ข้อความ ระบบชนิดข้อมูลครอบคลุมชนิดพื้นฐานแบบสเกลาร์ คอลเลกชันแบบเจเนริก ตัวเลขที่กำหนดขนาด เทนเซอร์ และชนิดรีจิสเตอร์สำหรับงาน GPU

ชนิดข้อมูลพื้นฐาน#

ชนิดข้อมูลบทบาทตัวอย่างลิเทอรัล
ข้อความสตริง Unicode"Salve, munde"
asciiโทเค็นเครื่องแบบความยาวคงที่'solum:lege'
i32จำนวนเต็มมีเครื่องหมาย42
f64จำนวนทศนิยม3.14
ตรรกะค่าบูลีนจริง, เท็จ
เปล่าหน่วย / ไม่มีค่า—
นัลค่า Null / ไม่มีอยู่นัล
อินสแตนซ์ระยะเวลา / จุดเวลาทันที—
jsonค่า JSON ระหว่างคอมไพล์{ "key": "value" }
ไบต์ลำดับไบต์ฐานสิบหก\|00ff\|

ชนิดตัวเลขที่กำหนดขนาด#

เขียนความกว้างในตำแหน่งชนิดข้อมูล นี่คือชนิดตัวเลข — รายการเดียวกับ Math in the ether:

ตระกูลความกว้าง
มีเครื่องหมายi8 i16 i32 i64
ไม่มีเครื่องหมายu8 u16 u32 u64
ทศนิยมd64
จำนวนเต็มไม่จำกัดinf
ทศนิยมลอยตัวf16 bf16 f32 f64
เริ่ม {
    คงที่ i32 narrow ← 7 ∷ i32
    คงที่ u64 wide ← 255 ∷ u64
    คงที่ f32 single ← 1.5 ∷ f32
}

เครื่องหมายความกว้างเปล่าคือชนิดข้อมูล

ชนิดข้อมูลที่รับค่า Null ได้#

ค่าที่รับ Null ได้ใช้ไวยากรณ์ยูเนียน T ∪ นัล:

ฟังก์ชัน find(ข้อความ key) → จํานวน ∪ นัล {
    คืน ว่างเปล่า
}

ฟังก์ชัน maybe() → ข้อความ ∪ นัล {
    คืน ว่างเปล่า
}

Faber ไม่มีไวยากรณ์ T? หรือ Option<T> ยูเนียนนี้ระบุไว้อย่างชัดเจน

นามแฝงชนิดข้อมูล#

ชนิดนามแฝง UserId = จํานวน

เจเนริก#

ฟังก์ชัน นามแฝงชนิดข้อมูล ชนิด และ สัญญา รับพารามิเตอร์ชนิดข้อมูลด้วยไวยากรณ์ <T>:

ฟังก์ชัน identitas<T>(T ค่า) → T {
    คืน ค่า
}

ฟังก์ชัน primum<T>(รายการ<T> res) → T ∪ นัล {
    คืน res.ตัวแรก()
}

รองรับการระบุอาร์กิวเมนต์ชนิดข้อมูล ณ จุดเรียกใช้โดยตรง:

ฟังก์ชัน identitas<T>(T ค่า) → T {
    คืน ค่า
}

เริ่ม {
    คงที่ จํานวน value ← identitas<จํานวน>(7)
}

คอลเลกชัน#

ชนิดข้อมูลบทบาทชวเลข
รายการ<T>คอลเลกชันแบบเรียงลำดับที่ปรับขนาดได้lf32, lu32
ตาราง<K, V>แมปคีย์-ค่า—
เทนเซอร์<T, Figura>บัฟเฟอร์หนาแน่นที่มีรูปร่างคงที่tf32[4], ti64[2,3]
กระจัดกระจาย<T, Figura>บัฟเฟอร์กระจัดกระจายที่มีรูปร่างคงที่sf32[4], si64[2,3]
อันตรภาคชนิดช่วง—
ชุด<T>เซตที่ไม่เรียงลำดับ—
เคอร์เซอร์<T>สตรีมแบบขี้เกียจ—
เริ่ม {
    คงที่ รายการ<จํานวน> nums ← [1, 2, 3]
    คงที่ ตาราง<ข้อความ, จํานวน> scores ← { "alice": 10, "bob": 20 }
}

ชนิดเทนเซอร์#

เทนเซอร์<T, Figura> คือคอนเทนเนอร์หนาแน่นที่มีรูปร่างคงที่:

รูปแบบความหมาย
เทนเซอร์<T, Figura>รูปแบบมาตรฐาน
เทนเซอร์<T, []>แรงก์ 0 (คอนเทนเนอร์สเกลาร์)
เทนเซอร์<T, _>ช่องสำหรับอนุมานรูปร่าง
เทนเซอร์<T, [N]>เวกเตอร์แรงก์ 1
เทนเซอร์<T, [N, M]>เมทริกซ์แรงก์ 2
เริ่ม {
    คงที่ เทนเซอร์<f32, []> scalar ← เซตว่าง
    คงที่ เทนเซอร์<จํานวน, [4]> row ← [1, 2, 3, 4] ↦ เทนเซอร์<จํานวน, [4]>
    คงที่ จํานวน ∪ นัล first ← row[0]
}

ชนิดข้อมูลแกนหลักสำหรับ GPU#

ระบบเลนสำหรับงาน GPU และรีจิสเตอร์จะรู้จักชนิดข้อมูลเหล่านี้ แพ็กเกจเป้าหมายที่ไม่รองรับฮาร์ดแวร์จะปฏิเสธชนิดข้อมูลเหล่านี้:

ฟังก์ชัน half(f16 x) → f16 { คืน x }

ฟังก์ชัน add(เมทริกซ์<f32, [2, 2]> a, เมทริกซ์<f32, [2, 2]> b) → เมทริกซ์<f32, [2, 2]> {
    คืน a.addita(b)
}

ฟังก์ชัน swap(อะตอมิก<i32> cell, i32 value) → i32 {
    คืน cell.exchange(value)
}

เครื่องหมายการยืมบนชนิดข้อมูล#

เครื่องหมายการยืม (จาก, ใน, เป็นเจ้าของ) สามารถปรากฏบนชนิดข้อมูลในตำแหน่งพารามิเตอร์ เพื่อระบุวิธีส่งค่า:

# shared borrow — caller retains ownership
functio imprime(de textus label) → vacuum { }

# mutable borrow — caller lends mutable access
functio duplica(in numerus value) → vacuum { }

# move — caller gives up ownership
functio consume(own textus buffer) → textus {
    redde buffer
}

นโยบายการเปรียบเทียบ#

ตัวดำเนินการกลุ่มพฤติกรรม
≡, ≠, ≢ความเท่ากันแบบตรงกันทุกประการต้องใช้ชนิดข้อมูลเดียวกัน; นัล เป็นข้อยกเว้น
≅, ≇ความเท่ากันตรงทั้งหมดหลังเลื่อนประเภทรวมความกว้างตัวเลขแล้วเทียบแบบตรงทั้งหมด
≈, ≉ความเท่ากันแบบคลาดเคลื่อนเข้าคู่ตามค่าคลาดเคลื่อน — ค่าเริ่มต้น isclose (rel_tol 1e-09); ตัวถูกดำเนินการตัวเลขเท่านั้น
<, ≤, >, ≥การเรียงลำดับใช้กับตัวเลข จุดเวลา และข้อความสเกลาร์
ภายในการมีค่าอยู่ในช่วงตัวเลขอยู่ในช่วง
ระหว่างการเป็นสมาชิกของคอลเลกชันองค์ประกอบอยู่ในคอลเลกชัน

Variables and binding#

Faber มีคีย์เวิร์ดสำหรับตัวแปรสามแบบและมีสัญลักษณ์การกำหนดค่าโดยเฉพาะ ความแตกต่างสำคัญอยู่ระหว่าง คงที่ (เขียนได้ครั้งเดียว) กับ แปร (กำหนดค่าใหม่ได้อย่างอิสระ) และระหว่าง ← (ลำดับการทำงานขณะรันไทม์) กับ = (รูปแบบฟิลด์เชิงโครงสร้าง)

คงที่ — การผูกค่าที่ไม่เปลี่ยนแปลง#

การผูกค่าด้วย คงที่ เขียนได้ครั้งเดียว สามารถประกาศพร้อมตัวกำหนดค่าเริ่มต้นหรือไม่มีก็ได้ หากประกาศโดยไม่มีตัวกำหนดค่าเริ่มต้น ต้องกำหนดค่าให้พอดีหนึ่งครั้งก่อนอ่านค่า การกำหนดค่าครั้งที่สองจะถูกปฏิเสธ

เริ่ม {
    คงที่ จํานวน count ← 0
    คงที่ ข้อความ name ← "Marcus"
    คงที่ _ inferred ← [1, 2, 3]
}

การกำหนดค่าเริ่มต้นภายหลัง:

เริ่ม {
    คงที่ จํานวน factor
    ถ้า จริง {
        factor ← 10
    }
    มิฉะนั้น {
        factor ← 100
    }
    บันทึก factor
}

แปร — การผูกค่าที่เปลี่ยนแปลงได้#

การผูกค่าด้วย แปร สามารถกำหนดค่าใหม่ได้อย่างอิสระ:

เริ่ม {
    แปร จํานวน count ← 0
    count ← count + 1
    count ← count * 2
}

อนุมานคงที่ — รูปแบบย่อของการผูกค่าคงที่แบบอนุมานชนิด#

อนุมานคงที่ เป็นรูปแบบย่อของ คงที่ _ — การผูกค่าที่ไม่เปลี่ยนแปลงซึ่งอนุมานชนิดข้อมูล:

เริ่ม {
    คงที่ _ salve ← "Salve"
    คงที่ _ ชื่อ ← "Marcus"
    คงที่ _ x ← 42

    # Deferred form
    คงที่ _ label
    label ← "deferred"
}

การผูกค่าขณะรันไทม์เทียบกับการกำหนดโครงสร้าง#

Faber แยกสิ่งที่ภาษาส่วนใหญ่มักรวมไว้ภายใต้ = ออกเป็นสองความหมาย:

สัญลักษณ์บทบาทใช้สำหรับ
←ลำดับการทำงานขณะรันไทม์การผูกค่าเริ่มต้น การกำหนดค่าใหม่ การเปลี่ยนแปลงค่า
=รูปแบบเชิงโครงสร้างชื่อฟิลด์ภายในลิเทอรัลและเมทาดาทา
ชนิด Point {
    คงที่ จํานวน x
    คงที่ จํานวน y
}

เริ่ม {
    # Runtime: ← attaches a value to a name at execution time
    แปร จํานวน count ← 0
    แปร ข้อความ label ← "ready"
    count ← count + 1

    # Structural: = defines field values inside a type literal
    คงที่ _ p ← Point { x = 10, y = 20 }
}

การดึงฟิลด์ด้วย ออก#

ออก ใช้ดึงฟิลด์จากค่าออกมาเป็นการผูกค่าในขอบเขตภายใน:

ชนิด Persona {
    คงที่ ข้อความ ชื่อ
    คงที่ จํานวน aetas
}

เริ่ม {
    คงที่ _ p ← Persona { ชื่อ = "Marcus", aetas = 30 }
    คงที่ ข้อความ ชื่อ ← p.nomen
    คงที่ จํานวน aetas ← p.aetas
    # prints "Marcus"
    บันทึก ชื่อ
}

การอัปเดตค่าตัวเลขที่เปลี่ยนแปลงได้#

ใช้ตัวดำเนินการแบบไบนารี + และ - ร่วมกับการกำหนดค่าเวลารันไทม์ ← เพื่ออัปเดตตำแหน่ง จํานวน ที่เปลี่ยนแปลงได้ ตัวดำเนินการทั้งสองต้องมีตัวถูกดำเนินการสองตัว และไม่ใช่คำสั่งแบบต่อท้าย:

เริ่ม {
    แปร จํานวน i ← 0
    # i becomes 1
    i ← i + 1
    # i becomes 0
    i ← i - 1
}

Collections#

Faber มีชนิดคอลเลกชันหลายชนิดที่คอมไพเลอร์เป็นผู้ดูแล เมธอดมาตรฐานของชนิดเหล่านี้อยู่ในคอมไพเลอร์ ไม่ได้อยู่ในไลบรารีมาตรฐาน

Lista — คอลเลกชันแบบลำดับที่ปรับขนาดได้แบบไดนามิก#

เริ่ม {
    คงที่ รายการ<จํานวน> empty ← เซตว่าง
    คงที่ _ numbers ← [1, 2, 3, 4, 5]
    คงที่ _ names ← ["Marcus", "Julia", "Gaius"]
    คงที่ _ nested ← [[1, 2], [3, 4]]
}

การกระจายสมาชิกด้วย กระจาย:

เริ่ม {
    คงที่ รายการ<จํานวน> a ← [1, 2, 3]
    คงที่ รายการ<จํานวน> b ← [4, 5, 6]
    คงที่ _ combined ← [กระจาย a, กระจาย b]
    คงที่ _ headed ← [0, กระจาย a, 99]
}

เมธอดสำคัญ: longitudo, accipe, appende, ผลรวม, primus, novissimus

Tabula — แมปแบบคีย์-ค่า#

เริ่ม {
    คงที่ ตาราง<ข้อความ, จํานวน> scores ← { "alice": 10, "bob": 20 }
}

Tensor — บัฟเฟอร์หนาแน่นที่มีรูปร่างตายตัว#

เริ่ม {
    คงที่ เทนเซอร์<f32, []> scalar ← เซตว่าง
    คงที่ เทนเซอร์<จํานวน, [4]> row ← [1, 2, 3, 4] ↦ เทนเซอร์<จํานวน, [4]>
    คงที่ จํานวน ∪ นัล first ← row[0]
}

ไวยากรณ์ย่อของ Tensor (สำหรับโค้ดที่เน้นการคำนวณเชิงตัวเลข):

เริ่ม {
    คงที่ tf32[] seed ← เซตว่าง
    คงที่ tf32[4] lanes ← seed.สร้างจากข้อมูลแบน([1.0, 2.0, 3.0, 4.0], [4])
}

เมธอดสำคัญ: forma, accipe, ponde, crea, structa, strue รวมถึง การคำนวณแบบสมาชิกต่อสมาชิก การคูณเมทริกซ์ (multiplicatio) และ การลดรูปค่า (ผลรวม, productum)

Sparsa — บัฟเฟอร์เบาบางที่มีรูปร่างตายตัว#

เริ่ม {
    คงที่ กระจัดกระจาย<f32, [2, 3]> sparse ← เซตว่าง
    sparse.ponde([0, 1], 4.0)
    sparse.ponde([1, 2], 9.0)

    # accipe returns the stored value, here 4.0
    บันทึก sparse.accipe([0, 1])
    # count of stored entries
    บันทึก sparse.nonnihil()
}

การแปลงระหว่างบัฟเฟอร์หนาแน่นและบัฟเฟอร์เบาบาง:

เริ่ม {
    คงที่ tf32[2, 2] dense ← [[1.0, 0.0], [0.0, 2.0]] ↦ เทนเซอร์<f32, [2, 2]>
    คงที่ sf32[2, 2] sparse ← dense ↦ กระจัดกระจาย<f32, [2, 2]>
    คงที่ tf32[2, 2] roundtrip ← sparse ↦ เทนเซอร์<f32, [2, 2]>
}

Cursors — สตรีมแบบประเมินค่าอย่างเลื่อนลอย#

เคอร์เซอร์<T> คือชนิดสตรีมแบบประเมินค่าอย่างเลื่อนลอย สร้างได้จากตัววนซ้ำของคอลเลกชัน มุมมอง รับ หรือฟังก์ชันสร้างค่า ใช้งานผ่าน วน ออก:

เริ่ม {
    คงที่ _ items ← [1, 2, 3]
    วน ออก items คงที่ item {
        บันทึก item
    }
}

Intervallum — ช่วงค่า#

# exclusive range: 0, 1, 2, 3, 4
วน ช่วง 0‥5 คงที่ i {
    บันทึก i
}
# inclusive range: 0, 1, 2, 3, 4, 5
วน ช่วง 0…5 คงที่ i {
    บันทึก i
}

‥ คือจุดสิ้นสุดของช่วงแบบไม่รวมค่า ส่วน … คือจุดสิ้นสุดของช่วงแบบรวมค่า

String and template literals#

Faber ใช้ความหมายของตัวคั่น โดยรูปแบบเครื่องหมายคำพูดแต่ละแบบหมายถึงรูปร่างของซอร์สโค้ดที่แตกต่างกัน รูปแบบเหล่านี้ไม่ใช่คำพ้องความหมายที่ใช้แทนกันได้

รูปแบบลิเทอรัล#

รูปแบบชนิดบทบาท
'…'asciiโทเคนเครื่องจักรแบบคงที่ ไม่รองรับ § และไม่รองรับ (…)
"…"ข้อความสตริง Unicode แบบบรรทัดสั้น โดย (…) จะทำการเรนเดอร์
«…»ข้อความUnicode แบบบล็อกหรือหลายบรรทัด โดย (…) จะทำการเรนเดอร์
… formaเทมเพลตที่บันทึกไว้ โดย (…) จะจับค่า
{ … }jsonเอกสาร JSON ระหว่างคอมไพล์
`…`ไบต์ไบต์ฐานสิบหกที่สร้างระหว่างคอมไพล์
[ … ]รายการ<T>ลิเทอรัลลิสต์ของ Faber

การใช้เทมเพลตสตริง#

Faber จัดรูปแบบข้อความด้วยการใช้เทมเพลตสตริง โดยใช้ลิเทอรัล "…" หรือ «…» ที่มีช่อง § แล้วตามด้วยอาร์กิวเมนต์ในวงเล็บ:

ฟังก์ชัน greet(ข้อความ ชื่อ) → ข้อความ {
    คืน "Salve, §!"(ชื่อ)
}

เริ่ม {
    คงที่ จํานวน pagina ← 3
    คงที่ จํานวน totum ← 10
    คงที่ ข้อความ code ← "200"
    คงที่ ข้อความ label ← "OK"
    คงที่ _ msg ← "Page § of §"(pagina, totum)
    คงที่ _ block ← "status: § (§)"(code, label)
}

กฎสำคัญ:

  • § (U+00A7) คือช่องของเทมเพลต
  • ช่องแบบระบุตำแหน่งใช้ §0, §1, … เพื่อกำหนดลำดับอย่างชัดเจน
  • ! ท้ายช่องเลือกการจัดรูปแบบเพื่อแสดงผล: "Salve, §!"(ชื่อ)
  • ส่วนต่อท้าย (args) คือการใช้เทมเพลต ไม่ใช่การเรียกฟังก์ชัน

สตริงแบบบล็อก#

บล็อกหลายบรรทัดใช้เครื่องหมายกีโยแมต์ «…»:

เริ่ม {
    คงที่ _ sql ← «
        select id, email
        from accounts
    »
}

เทมเพลตที่บันทึกไว้ (forma)#

เทมเพลตที่ใช้เครื่องหมายแบ็กทิกจะจับข้อความและพารามิเตอร์ไว้โดยไม่เรนเดอร์ เหมาะสำหรับเพย์โหลด SQL/URL ที่ผูกค่าอย่างปลอดภัย:

เริ่ม {
    คงที่ จํานวน user_id ← 42
    คงที่ _ query ← `select * from users where id = §`(user_id)
}

JSON แบบอินไลน์#

{ … } เปล่าคือ JSON แบบอินไลน์ ซึ่งเป็นเอกสาร json ที่สร้างระหว่างคอมไพล์ ไม่ใช่ออบเจ็กต์ Faber แบบไม่ระบุชนิด คีย์ต้องเป็นสตริงที่ใส่เครื่องหมายคำพูด และคั่นด้วย ::

เริ่ม {
    คงที่ _ empty ← {}
    คงที่ _ user ← { "name": "Marcus", "age": 30, "active": true }
    คงที่ _ nested ← { "meta": { "version": 1 }, "tags": ["alpha", "beta"] }
}

สำหรับการสร้าง ชนิด แบบระบุชนิด ให้ใช้ชื่อชนิดและรูปแบบฟิลด์ที่มี =:

ชนิด Point {
    คงที่ จํานวน x
    คงที่ จํานวน y
}

เริ่ม {
    คงที่ _ p ← Point { x = 10, y = 20 }
}

Nullability and optionality#

Faber แยกความแตกต่างระหว่างการไม่มีค่าในค่าหนึ่ง กับการระบุให้เป็นทางเลือก ณ จุดประกาศ

ค่าที่อาจไม่มีค่า — T ∪ นัล#

ใช้ T ∪ นัล เมื่อค่านั้นอาจไม่มีค่า:

ฟังก์ชัน find(ข้อความ key) → จํานวน ∪ นัล {
    คืน ว่างเปล่า
}

ฟังก์ชัน divide(จํานวน a, จํานวน b) → จํานวน ∪ นัล {
    ถ้า b ≡ 0 ดังนั้น คืน ว่างเปล่า
    คืน a / b
}

ช่องประกาศที่เป็นทางเลือก — สมัครใจ#

ใช้ สมัครใจ ต่อท้ายชื่อ เมื่อผู้เรียกใช้หรือคอนสตรักเตอร์อาจละเว้นพารามิเตอร์หรือฟิลด์นั้น:

ฟังก์ชัน connect(ข้อความ host, จํานวน port สมัครใจ) → เปล่า {
}

ชนิด User {
    คงที่ ข้อความ email สมัครใจ
}

เครื่องหมายการยืมสามารถใช้ร่วมกับพารามิเตอร์ที่เป็นทางเลือกได้:

ฟังก์ชัน process(จาก จํานวน depth สมัครใจ) → เปล่า {
}

การยืนยันว่าไม่เป็นค่าว่าง — !#

ใช้ !., ![, !( เพื่อยืนยันว่าค่าที่อาจไม่มีค่าไม่ใช่ นัล:

ชนิด Box {
    คงที่ จํานวน ∪ นัล val
}

เริ่ม {
    คงที่ Box ∪ นัล maybe_name ← Box { val = 7 }
    คงที่ _ name ← maybe_name!.val
}

การยืนยันว่าไม่เป็นค่าว่างกับ นัล จะยุติการทำงานขณะรันไทม์

การรวมค่าเมื่อเป็นค่าว่าง — vel#

เริ่ม {
    คงที่ ข้อความ ∪ นัล provided ← ว่างเปล่า
    คงที่ _ name ← provided หรือว่าง "default"
}

ไม่รู้#

ไม่รู้ คือชนิดข้อมูลไม่ทราบค่าระดับบนสุดสำหรับทางออกชั่วคราวและกรณีที่ความรู้ยังไม่สมบูรณ์ ไม่ใช่กลไกสำหรับค่าที่อาจเป็นค่าว่าง

Conversion and construction#

ตัวดำเนินการแปลงที่สำคัญมีสองแบบ แบบหนึ่งใช้ขณะรันไทม์ และอีกแบบใช้ขณะคอมไพล์:

# runtime แปลง
เริ่ม {
    คงที่ _ parsed ← "42" ↦ จํานวน ⊥ 0
    # static ascription
    คงที่ จํานวน value ← 7
    คงที่ _ text ← value ∷ ข้อความ
}

การแปลงขณะรันไทม์ — ↦#

ใช้ ↦ สำหรับการแปลงขณะรันไทม์ โดยเฉพาะการแปลงจากข้อความหรือการบังคับแปลงชนิดข้อมูลที่อาจล้มเหลว กำหนดการกู้คืนแบบอินไลน์ด้วย ⊥:

เริ่ม {
    คงที่ ข้อความ input ← "9"
    คงที่ _ n ← "42" ↦ จํานวน ⊥ 0
    คงที่ _ safe ← input ↦ จํานวน ⊥ 0
}

การสร้างค่าตามชนิดข้อมูล:

เริ่ม {
    คงที่ ข้อความ path ← "/etc/hosts"
    คงที่ _ lanes ← [1.0, 2.0, 3.0, 4.0] ↦ เวกเตอร์<f32, 4>
    คงที่ _ body ← ถึง 'solum:lege' (path) ↦ ข้อความ
}

การระบุชนิดข้อมูลแบบคงที่ — ∷#

ใช้ ∷ เพื่อระบุชนิดข้อมูลแบบคงที่อย่างชัดเจน ตัวดำเนินการนี้วางต่อท้าย และขับเคลื่อนด้วยชนิดข้อมูลเป้าหมาย:

เริ่ม {
    คงที่ จํานวน value ← 7
    คงที่ _ x ← 7 ∷ i32
    คงที่ _ text ← value ∷ ข้อความ
}

การรวมค่าเมื่อเป็นค่าว่าง — หรือว่าง#

ใช้ หรือว่าง สำหรับการรวมค่าเมื่อค่าหนึ่งเป็น นัล:

เริ่ม {
    คงที่ ข้อความ ∪ นัล provided_name ← ว่างเปล่า
    คงที่ _ name ← provided_name หรือว่าง "default"
}