Types and values
Data types#
Faber มีระบบชนิดข้อมูลแบบสถิตที่ให้ชนิดข้อมูลมาก่อน ทุกการประกาศจะวางชนิดข้อมูลไว้ก่อนชื่อ: textus nomen ไม่ใช่ nomen: textus ระบบชนิดข้อมูลครอบคลุมชนิดพื้นฐานแบบสเกลาร์ คอลเลกชันแบบเจเนริก ตัวเลขที่กำหนดขนาด เทนเซอร์ และชนิดรีจิสเตอร์สำหรับงาน GPU
ชนิดข้อมูลพื้นฐาน#
| ชนิดข้อมูล | บทบาท | ตัวอย่างลิเทอรัล |
|---|---|---|
ข้อความ | สตริง Unicode | "Salve, munde" |
ascii | โทเค็นเครื่องแบบความยาวคงที่ | 'solum:lege' |
จำนวน | จำนวนเต็มมีเครื่องหมาย (ค่าเริ่มต้นคือ i64) | 42 |
เศษ | จำนวนทศนิยม (ค่าเริ่มต้นคือ f64) | 3.14 |
ตรรกะ | ค่าบูลีน | จริง, เท็จ |
เปล่า | หน่วย / ไม่มีค่า | — |
ว่าง | ค่า Null / ไม่มีอยู่ | ว่าง |
อินสแตนซ์ | ระยะเวลา / จุดเวลาทันที | — |
json | ค่า JSON ระหว่างคอมไพล์ | { "key": "value" } |
ไบต์ | ลำดับไบต์ฐานสิบหก | \|00ff\| |
ชนิดตัวเลขที่กำหนดขนาด#
จำนวน และ เศษ มีความกว้างเริ่มต้น (i64 และ f64) และมีรูปแบบที่ระบุความกว้างได้อย่างชัดเจน:
คงที่ จำนวน<i32> narrow ← 7 ∷ จำนวน<i32>
คงที่ จำนวน<u64> wide ← 255 ∷ จำนวน<u64>
คงที่ f32 single ← 1.5 ∷ f32สามารถใช้ชวเลขความกว้างในตำแหน่งชนิดข้อมูลได้: i8 … u64, f16, f32, f64 เทียบเท่ากับ numerus<W> / fractus<W>
ชนิดข้อมูลที่รับค่า Null ได้#
ค่าที่รับ Null ได้ใช้ไวยากรณ์ยูเนียน T ∪ nihil:
ฟังก์ชัน find(ข้อความ key) → จำนวน ∪ ว่าง {
คืน ว่าง
}
ฟังก์ชัน maybe() → ข้อความ ∪ ว่าง {
คืน ว่าง
}Faber ไม่มีไวยากรณ์ T? หรือ Option<T> ยูเนียนนี้ระบุไว้อย่างชัดเจน
นามแฝงชนิดข้อมูล#
ชนิดนามแฝง UserId = จำนวนเจเนริก#
ฟังก์ชัน นามแฝงชนิดข้อมูล ชนิด และ implendum รับพารามิเตอร์ชนิดข้อมูลด้วยไวยากรณ์ <T>:
ฟังก์ชัน identitas<T>(T valor) → T {
คืน valor
}
ฟังก์ชัน primum<T>(รายการ<T> res) → T ∪ ว่าง {
คืน res.primus()
}รองรับการระบุอาร์กิวเมนต์ชนิดข้อมูล ณ จุดเรียกใช้โดยตรง:
ฟังก์ชัน identitas<T>(T valor) → T {
คืน valor
}
คงที่ จำนวน value ← identitas<จำนวน>(7)คอลเลกชัน#
| ชนิดข้อมูล | บทบาท | ชวเลข |
|---|---|---|
lista<T> | คอลเลกชันแบบเรียงลำดับที่ปรับขนาดได้ | lf32, lu32 |
tabula<K, V> | แมปคีย์-ค่า | — |
tensor<T, Figura> | บัฟเฟอร์หนาแน่นที่มีรูปร่างคงที่ | tf32[4], ti64[2,3] |
sparsa<T, Figura> | บัฟเฟอร์กระจัดกระจายที่มีรูปร่างคงที่ | sf32[4], si64[2,3] |
intervallum | ชนิดช่วง | — |
copia<T> | เซตที่ไม่เรียงลำดับ | — |
cursor<T> | สตรีมแบบขี้เกียจ | — |
คงที่ รายการ<จำนวน> nums ← [1, 2, 3]
คงที่ ตาราง<ข้อความ, จำนวน> scores ← { "alice": 10, "bob": 20 }ชนิดเทนเซอร์#
tensor<T, Figura> คือคอนเทนเนอร์หนาแน่นที่มีรูปร่างคงที่:
| รูปแบบ | ความหมาย |
|---|---|
tensor<T, Figura> | รูปแบบมาตรฐาน |
tensor<T, []> | แรงก์ 0 (คอนเทนเนอร์สเกลาร์) |
tensor<T, _> | ช่องสำหรับอนุมานรูปร่าง |
tensor<T, [N]> | เวกเตอร์แรงก์ 1 |
tensor<T, [N, M]> | เมทริกซ์แรงก์ 2 |
คงที่ เทนเซอร์<f32, []> scalar ← เซตว่าง
คงที่ เทนเซอร์<จำนวน, [4]> vector ← [1, 2, 3, 4] ↦ เทนเซอร์<จำนวน, [4]>
คงที่ จำนวน ∪ ว่าง first ← vector[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(ex textus buffer) → textus {
redde buffer
}นโยบายการเปรียบเทียบ#
| ตัวดำเนินการ | กลุ่ม | พฤติกรรม |
|---|---|---|
≡, ≠ | ความเท่ากันแบบตรงกันทุกประการ | ต้องใช้ชนิดข้อมูลเดียวกัน; ว่าง เป็นข้อยกเว้น |
≈, ≉ | ความเท่ากันของค่าเชิงตัวเลข | ใช้ได้เฉพาะลำดับชั้นชนิดตัวเลข |
<, ≤, >, ≥ | การเรียงลำดับ | ใช้กับตัวเลข จุดเวลา และข้อความสเกลาร์ |
intra | การมีค่าอยู่ในช่วง | ตัวเลขอยู่ในช่วง |
inter | การเป็นสมาชิกของคอลเลกชัน | องค์ประกอบอยู่ในคอลเลกชัน |
Variables and binding#
Faber มีคีย์เวิร์ดสำหรับตัวแปรสามแบบและมีสัญลักษณ์การกำหนดค่าโดยเฉพาะ ความแตกต่างสำคัญอยู่ระหว่าง คงที่ (เขียนได้ครั้งเดียว) กับ แปร (กำหนดค่าใหม่ได้อย่างอิสระ) และระหว่าง ← (ลำดับการทำงานขณะรันไทม์) กับ = (รูปแบบฟิลด์เชิงโครงสร้าง)
fixum — การผูกค่าที่ไม่เปลี่ยนแปลง#
การผูกค่าด้วย คงที่ เขียนได้ครั้งเดียว สามารถประกาศพร้อมตัวกำหนดค่าเริ่มต้นหรือไม่มีก็ได้ หากประกาศโดยไม่มีตัวกำหนดค่าเริ่มต้น ต้องกำหนดค่าให้พอดีหนึ่งครั้งก่อนอ่านค่า การกำหนดค่าครั้งที่สองจะถูกปฏิเสธ
คงที่ จำนวน count ← 0
คงที่ ข้อความ name ← "Marcus"
คงที่ รายการ<จำนวน> inferred ← [1, 2, 3]การกำหนดค่าเริ่มต้นภายหลัง:
เริ่ม {
คงที่ จำนวน factor
ถ้า จริง {
factor ← 10
}
มิฉะนั้น {
factor ← 100
}
บันทึก factor
}varia — การผูกค่าที่เปลี่ยนแปลงได้#
การผูกค่าด้วย แปร สามารถกำหนดค่าใหม่ได้อย่างอิสระ:
เริ่ม {
แปร จำนวน count ← 0
count ← count + 1
count ← count * 2
}sit — รูปแบบย่อของการผูกค่าคงที่แบบอนุมานชนิด#
sit เป็นรูปแบบย่อของ fixum _ — การผูกค่าที่ไม่เปลี่ยนแปลงซึ่งอนุมานชนิดข้อมูล:
เริ่ม {
คงที่ ข้อความ salve ← "Salve"
คงที่ ข้อความ nomen ← "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
คงที่ Point p ← Point {x = 10, y = 20}
}การดึงฟิลด์ด้วย ex#
ออก ใช้ดึงฟิลด์จากค่าออกมาเป็นการผูกค่าในขอบเขตภายใน:
ชนิด Persona {
ข้อความ nomen
จำนวน aetas
}
เริ่ม {
คงที่ Persona p ← Persona {nomen = "Marcus", aetas = 30}
คงที่ ข้อความ nomen ← p.nomen
คงที่ จำนวน aetas ← p.aetas
# prints "Marcus"
บันทึก nomen
}การเพิ่มและลดค่าต่อท้าย#
⊕ และ ⊖ เป็นคำสั่งเพิ่มหรือลดค่าต่อท้ายสำหรับตำแหน่ง จำนวน ที่เปลี่ยนแปลงได้ คำสั่งเหล่านี้ใช้ได้เฉพาะในรูปคำสั่งเท่านั้น — ไม่มีค่าผลลัพธ์แบบนิพจน์ และไม่มีรูปนำหน้า:
เริ่ม {
แปร จำนวน i ← 0
# i becomes 1
i ⊕
# i becomes 0
i ⊖
}Collections#
Faber มีชนิดคอลเลกชันหลายชนิดที่คอมไพเลอร์เป็นผู้ดูแล เมธอดมาตรฐานของชนิดเหล่านี้อยู่ในคอมไพเลอร์ ไม่ได้อยู่ในไลบรารีมาตรฐาน
Lista — คอลเลกชันแบบลำดับที่ปรับขนาดได้แบบไดนามิก#
คงที่ รายการ<จำนวน> empty ← เซตว่าง
คงที่ รายการ<จำนวน> numbers ← [1, 2, 3, 4, 5]
คงที่ รายการ<ข้อความ> names ← ["Marcus", "Julia", "Gaius"]
คงที่ รายการ<รายการ<จำนวน>> nested ← [[1, 2], [3, 4]]การกระจายสมาชิกด้วย sparge:
คงที่ รายการ<จำนวน> a ← [1, 2, 3]
คงที่ รายการ<จำนวน> b ← [4, 5, 6]
คงที่ รายการ<จำนวน> combined ← [กระจาย a, กระจาย b]
คงที่ รายการ<จำนวน> headed ← [0, กระจาย a, 99]เมธอดสำคัญ: longitudo, accipe, appende, summa, primus, novissimus
Tabula — แมปแบบคีย์-ค่า#
คงที่ ตาราง<ข้อความ, จำนวน> scores ← { "alice": 10, "bob": 20 }Tensor — บัฟเฟอร์หนาแน่นที่มีรูปร่างตายตัว#
คงที่ เทนเซอร์<f32, []> scalar ← เซตว่าง
คงที่ เทนเซอร์<จำนวน, [4]> vector ← [1, 2, 3, 4] ↦ เทนเซอร์<จำนวน, [4]>
คงที่ จำนวน ∪ ว่าง first ← vector[0]ไวยากรณ์ย่อของ Tensor (สำหรับโค้ดที่เน้นการคำนวณเชิงตัวเลข):
คงที่ เทนเซอร์<f32, []> seed ← เซตว่าง
คงที่ เทนเซอร์<f32, [4]> lanes ← seed.strue([1.0, 2.0, 3.0, 4.0], [4])เมธอดสำคัญ: forma, accipe, ponde, crea, structa, strue รวมถึง
การคำนวณแบบสมาชิกต่อสมาชิก การคูณเมทริกซ์ (multiplicatio) และ
การลดรูปค่า (summa, 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()
}การแปลงระหว่างบัฟเฟอร์หนาแน่นและบัฟเฟอร์เบาบาง:
คงที่ เทนเซอร์<f32, [2, 2]> dense ← [[1.0, 0.0], [0.0, 2.0]] ↦ เทนเซอร์<f32, [2, 2]>
คงที่ กระจัดกระจาย<f32, [2, 2]> sparse ← dense ↦ กระจัดกระจาย<f32, [2, 2]>
คงที่ เทนเซอร์<f32, [2, 2]> roundtrip ← sparse ↦ เทนเซอร์<f32, [2, 2]>Cursors — สตรีมแบบประเมินค่าอย่างเลื่อนลอย#
cursor<T> คือชนิดสตรีมแบบประเมินค่าอย่างเลื่อนลอย สร้างได้จากตัววนซ้ำของคอลเลกชัน
มุมมอง tuus หรือฟังก์ชันสร้างค่า ใช้งานผ่าน itera ex:
คงที่ รายการ<จำนวน> 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 ระหว่างคอมไพล์ | ||
| ` | … | ` | ไบต์ | ไบต์ฐานสิบหกที่สร้างระหว่างคอมไพล์ |
[ … ] | lista<T> | ลิเทอรัลลิสต์ของ Faber |
การใช้เทมเพลตสตริง#
Faber จัดรูปแบบข้อความด้วยการใช้เทมเพลตสตริง โดยใช้ลิเทอรัล "…" หรือ «…» ที่มีช่อง § แล้วตามด้วยอาร์กิวเมนต์ในวงเล็บ:
ฟังก์ชัน greet(ข้อความ nomen) → ข้อความ {
คืน "Salve, §!"(nomen)
}
คงที่ จำนวน pagina ← 3
คงที่ จำนวน totum ← 10
คงที่ ข้อความ code ← "200"
คงที่ ข้อความ label ← "OK"
คงที่ ข้อความ msg ← "Page § of §"(pagina, totum)
คงที่ ข้อความ block ← "status: § (§)"(code, label)กฎสำคัญ:
§(U+00A7) คือช่องของเทมเพลต- ช่องแบบระบุตำแหน่งใช้
§0,§1, … เพื่อกำหนดลำดับอย่างชัดเจน !ท้ายช่องเลือกการจัดรูปแบบเพื่อแสดงผล:"Salve, §!"(nomen)- ส่วนต่อท้าย
(args)คือการใช้เทมเพลต ไม่ใช่การเรียกฟังก์ชัน
สตริงแบบบล็อก#
บล็อกหลายบรรทัดใช้เครื่องหมายกีโยแมต์ «…»:
คงที่ ข้อความ sql ← «
select id, email
from accounts
»เทมเพลตที่บันทึกไว้ (forma)#
เทมเพลตที่ใช้เครื่องหมายแบ็กทิกจะจับข้อความและพารามิเตอร์ไว้โดยไม่เรนเดอร์ เหมาะสำหรับเพย์โหลด SQL/URL ที่ผูกค่าอย่างปลอดภัย:
คงที่ จำนวน user_id ← 42
คงที่ forma query ← `select * from users where id = §`(user_id)JSON แบบอินไลน์#
{ … } เปล่าคือ JSON แบบอินไลน์ ซึ่งเป็นเอกสาร json ที่สร้างระหว่างคอมไพล์ ไม่ใช่ออบเจ็กต์ Faber แบบไม่ระบุชนิด คีย์ต้องเป็นสตริงที่ใส่เครื่องหมายคำพูด และคั่นด้วย ::
คงที่ json empty ← {}
คงที่ json user ← { "name": "Marcus", "age": 30, "active": true }
คงที่ json nested ← { "meta": { "version": 1 }, "tags": ["alpha", "beta"] }สำหรับการสร้าง ชนิด แบบระบุชนิด ให้ใช้ชื่อชนิดและรูปแบบฟิลด์ที่มี =:
ชนิด Point {
จำนวน x
จำนวน y
}
คงที่ Point p ← Point {x = 10, y = 20}Nullability and optionality#
Faber แยกความแตกต่างระหว่างการไม่มีค่าในค่าหนึ่ง กับการระบุให้เป็นทางเลือก ณ จุดประกาศ
ค่าที่อาจไม่มีค่า — T ∪ nihil#
ใช้ T ∪ nihil เมื่อค่านั้นอาจไม่มีค่า:
ฟังก์ชัน find(ข้อความ key) → จำนวน ∪ ว่าง {
คืน ว่าง
}
ฟังก์ชัน divide(จำนวน a, จำนวน b) → จำนวน ∪ ว่าง {
ถ้า b ≡ 0 ดังนั้น คืน ว่าง
คืน a / b
}ช่องประกาศที่เป็นทางเลือก — sponte#
ใช้ sponte ต่อท้ายชื่อ เมื่อผู้เรียกใช้หรือคอนสตรักเตอร์อาจละเว้นพารามิเตอร์หรือฟิลด์นั้น:
ฟังก์ชัน connect(ข้อความ host, จำนวน port สมัครใจ) → เปล่า {
}
ชนิด User {
ข้อความ email สมัครใจ
}เครื่องหมายการยืมสามารถใช้ร่วมกับพารามิเตอร์ที่เป็นทางเลือกได้:
ฟังก์ชัน process(จาก จำนวน depth สมัครใจ) → เปล่า {
}การยืนยันว่าไม่เป็นค่าว่าง — !#
ใช้ !., ![, !( เพื่อยืนยันว่าค่าที่อาจไม่มีค่าไม่ใช่ ว่าง:
ชนิด Box {
จำนวน ∪ ว่าง val
}
คงที่ Box ∪ ว่าง maybe_name ← Box {val = 7}
คงที่ จำนวน ∪ ว่าง name ← maybe_name!.valการยืนยันว่าไม่เป็นค่าว่างกับ ว่าง จะยุติการทำงานขณะรันไทม์
การรวมค่าเมื่อเป็นค่าว่าง — vel#
คงที่ ข้อความ ∪ ว่าง provided ← ว่าง
คงที่ ข้อความ name ← provided หรือว่าง "default"ignotum#
ignotum คือชนิดข้อมูลไม่ทราบค่าระดับบนสุดสำหรับทางออกชั่วคราวและกรณีที่ความรู้ยังไม่สมบูรณ์ ไม่ใช่กลไกสำหรับค่าที่อาจเป็นค่าว่าง
Conversion and construction#
ตัวดำเนินการแปลงที่สำคัญมีสองแบบ แบบหนึ่งใช้ขณะรันไทม์ และอีกแบบใช้ขณะคอมไพล์:
# runtime conversion
คงที่ จำนวน parsed ← "42" ↦ จำนวน
# static ascription
คงที่ จำนวน value ← 7
คงที่ ข้อความ text ← value ∷ ข้อความการแปลงขณะรันไทม์ — ↦#
ใช้ ↦ สำหรับการแปลงขณะรันไทม์ โดยเฉพาะการแปลงจากข้อความหรือการบังคับแปลงชนิดข้อมูลที่อาจล้มเหลว กำหนดการกู้คืนแบบอินไลน์ด้วย ⇥:
คงที่ ข้อความ input ← "9"
คงที่ จำนวน n ← "42" ↦ จำนวน
คงที่ จำนวน safe ← input ↦ จำนวน ⇥ 0การสร้างค่าตามชนิดข้อมูล:
คงที่ ข้อความ path ← "/etc/hosts"
คงที่ เวกเตอร์<f32, 4> lanes ← [1.0, 2.0, 3.0, 4.0] ↦ เวกเตอร์<f32, 4>
คงที่ ข้อความ body ← ถึง 'solum:lege' (path) ↦ ข้อความการระบุชนิดข้อมูลแบบคงที่ — ∷#
ใช้ ∷ เพื่อระบุชนิดข้อมูลแบบคงที่อย่างชัดเจน ตัวดำเนินการนี้วางต่อท้าย และขับเคลื่อนด้วยชนิดข้อมูลเป้าหมาย:
คงที่ จำนวน value ← 7
คงที่ จำนวน<i32> x ← 7 ∷ จำนวน<i32>
คงที่ ข้อความ text ← value ∷ ข้อความการรวมค่าเมื่อเป็นค่าว่าง — vel#
ใช้ vel สำหรับการรวมค่าเมื่อค่าหนึ่งเป็น ว่าง:
คงที่ ข้อความ ∪ ว่าง provided_name ← ว่าง
คงที่ ข้อความ name ← provided_name หรือว่าง "default"