Thử thách
Thách thức của bạn là thiết kế một trình thông dịch cho một ngôn ngữ giống như ngôn ngữ, từ đó sẽ được đặt ra: GLisp . Mã chương trình cho GLisp sẽ bao gồm một lượng biểu thức lồng nhau tùy ý được biểu thị bằng dấu ngoặc, theo mẫu sau:
(func arg1 arg2 ...)
Lưu ý rằng trình thông dịch phải cho phép các ký tự khoảng trắng bên ngoài trước và sau dấu ngoặc, hàm và đối số.
Các loại
Bạn sẽ thực hiện bốn loại, Integer, List, Boolean và Function. Các số nguyên và giá trị Boolean có thể được chèn rõ ràng vào mã nguồn bằng cú pháp riêng của chúng. Trình thông dịch của bạn phải cho rằng việc chạy các ký tự số biểu thị một Số nguyên (bạn không phải thực hiện cú pháp để chèn rõ ràng các số nguyên âm). Trình thông dịch của bạn cũng phải thừa nhận rằng true
và false
được chỉ định các giá trị Boolean. Các chức năng không thể được xác định rõ ràng bởi người dùng và sẽ luôn trả về một giá trị duy nhất (Danh sách có độ dài bất kỳ được tính là một giá trị).
Chức năng
Các chức năng sau đây được yêu cầu thực hiện và có định dạng Chức năng , Arity . Nếu một Arity n
được tiến hành bằng dấu cộng, thì điều đó biểu thị n
hoặc nhiều đối số. Bạn có thể giả định rằng tất cả các đối số được cung cấp cho một hàm là cùng loại, trừ khi được quy định cụ thể khác. Bạn cũng có thể cho rằng nếu không có hành vi nào được chỉ định cho loại certian, thì bạn có thể cho rằng không có đối số nào của hàm đó sẽ thuộc loại đó. Các đối số sẽ được gọi là trong sơ đồ sau:
(func argument1 argument2 ... argumentn)
+ , 2+
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về tổng của các đối số
- Nếu tất cả các đối số thuộc loại Danh sách , bạn phải trả về cách ghép các đối số theo thứ tự tăng dần (
arg1+arg2+ ...
) - Nếu tất cả các đối số thuộc loại Boolean , bạn phải trả về logic Tất cả các chuỗi đối số
(+ 1 2 3 4 5) -> 15
(+ (list 1 2) (list 3 4)) -> (list 1 2 3 4)
(+ true true true) -> true
- , 2+
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về sự khác biệt của các đối số (
arg1-arg2- ...
) - Nếu tất cả các đối số thuộc loại Boolean , bạn phải trả về logic Bất kỳ chuỗi đối số nào
(- 8 4 3) -> 1
(- 0 123) -> -123
(- true false false true false) -> true
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về sự khác biệt của các đối số (
* , 2+
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về sản phẩm của các đối số
- Nếu một đối số thuộc loại Danh sách và đối số còn lại thuộc loại Số nguyên (bạn có thể cho rằng đây sẽ chỉ là đối số duy nhất được cung cấp), bạn phải trả về Danh sách mới với các mục trong các
arg1
lần lặp lạiarg2
. (* 1 2 3 4 5) -> 120
(* (list 1 2 3) 2) -> (list 1 2 3 1 2 3)
/ , 2+
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về thương số của các đối số (
arg/arg2/ ...
) (bạn có thể giả sử rằng phép chia được thực hiện tuần tự và phần thập phân ở mỗi bước được cắt ngắn) - Nếu một đối số thuộc loại Danh sách và đối số còn lại thuộc loại Hàm , thì bạn phải trả về Danh sách kết quả sau khi
arg2
đã được ánh xạ qua mọi giá trị (/ 100 10 3) -> 3
(/ (list 1 2 3) inc) -> (list 2 3 4)
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về thương số của các đối số (
% , 2
- Nếu tất cả các đối số thuộc kiểu Integer , bạn phải trả về mô-đun của các đối số
(% 4 2) -> 0
= , 2+
- Nếu cả loại và giá trị của tất cả các đối số đều giống nhau, bạn phải trả về true. Nếu không, trả lại sai.
(= 0 0 0) -> true
(= 0 false (list)) -> false
danh sách , 0+
- Bạn phải trả về một danh sách tất cả các đối số, bất kể loại nào. Nếu không có đối số nào được đưa ra, thì bạn phải trả về một danh sách trống
(list 3 4 (list 5)) -> (list 3 4 (list 5))
bao gồm , 1
- Nếu đối số thuộc kiểu Integer , bạn phải trả về số nguyên tăng thêm một
- Nếu đối số thuộc loại Danh sách , bạn phải trả về Danh sách được xoay theo chiều kim đồng hồ một vòng quay duy nhất
(inc 1) -> 2
(inc (list 1 2 3)) -> (list 3 1 2)
ngày 1 tháng 12
- Nếu đối số thuộc kiểu Integer , bạn phải trả về số nguyên bị giảm bởi một
- Nếu đối số thuộc loại Danh sách , bạn phải trả về Danh sách được xoay ngược chiều kim đồng hồ một vòng quay
(dec 1) -> 0
(dec (list 1 2 3)) -> (list 2 3 1)
nếu , 3
- Nếu đưa ra ba đối số thuộc bất kỳ loại nào: Nếu giá trị thật của giá trị
arg1
là true, returnarg2
, other returnarg3
(if (not (list 1)) 8 false) -> false
- Nếu đưa ra ba đối số thuộc bất kỳ loại nào: Nếu giá trị thật của giá trị
không , 1
- Nếu đưa ra một đối số của bất kỳ loại nào, nếu giá trị thật của
arg1
Sai, trả vềtrue
, trả về khácfalse
. (not (list)) -> true
- Nếu đưa ra một đối số của bất kỳ loại nào, nếu giá trị thật của
len , 1
- Nếu được cung cấp một đối số của Danh sách loại , trả về độ dài của
arg1
(len (list 4 2 true (list 3) (list))) -> 5
- Nếu được cung cấp một đối số của Danh sách loại , trả về độ dài của
Bảng chân lý :
0, (list), false -> false
, nơi (list)
biểu thị một danh sách trống. Mọi thứ khác là true
.
Trình thông dịch của bạn có thể là một chương trình đầy đủ đọc đầu vào nguồn từ stdin hoặc tệp hoặc hàm lấy nguồn dưới dạng chuỗi và trả về giá trị đầu ra.
Nếu chọn cái trước, đầu ra cho Số nguyên chỉ đơn giản là số, đối với Booleans làtrue
hoặc false
, và đối với danh sách là một chuỗi các giá trị được phân tách bằng dấu cách được đặt trong ngoặc (ví dụ: (1 2 3 4 (5 6 7))
biểu thị (list 1 2 3 4 (list 5 6 7))
).
Nếu chọn cái sau, giá trị phải được trả về trong loại tương ứng của ngôn ngữ thực hiện hoặc, nếu không có loại tương tự tồn tại, một loại tùy chỉnh. Danh sách có thể được trả về dưới dạng Mảng hoặc vectơ nếu ngôn ngữ không có loại Danh sách , Booleans phải được trả về dưới dạng loại Boolean trong ngôn ngữ hoặc loại tùy chỉnh nếu ngôn ngữ không hỗ trợ chúng.
Các trường hợp thử nghiệm
(list 1 2 3 (list 4 5 true)) -> (1 2 3 (4 5 true))
(/ 4000 (+ 1 2 3 4 (* 5 8))) -> 80
(+ (not (- (len (list 5 6 7)) (/ 10 3))) true) -> true
(if ( len (list ) ) 4 (if (+ (= 8 8 8) (not (list 4))) 8 5)) -> 5
Làm rõ
- Thông dịch viên của bạn có thể xử lý đầu vào không hợp lệ theo bất kỳ cách nào bạn chọn, nhưng nó không được ném ngoại lệ (mặc dù, nó có thể in thông báo lỗi và thoát trơn tru)
- Các hàm sẽ luôn đánh giá các đối số từ trái sang phải
- Đầu vào không hợp lệ là bất kỳ đầu vào nào về mặt cú pháp không chính xác. Điều này bao gồm, nhưng không giới hạn ở các dấu ngoặc không khớp, chia cho 0 và các hàm được áp dụng một phần (trừ khi đi lấy tiền thưởng)
- Đối với
=
, nếu bất kỳ giá trị nào khác nhau hoặc bất kỳ loại nào khác nhau, hãy trả vềfalse
Tiền thưởng
- Điểm * 0,8 nếu bạn hỗ trợ các chức năng được áp dụng một phần. Ví dụ,
((+ 2) 3)
sẽ giống như(+ 2 3)
, nhưng cho phép những thứ như(/ (list 1 2 3) (+ 2))
. Bạn có thể giả sử rằng một hàm được áp dụng một phần nếu nó nhận được ít hơn số lượng đối số tối thiểu của nó - Điểm * 0,85 nếu bạn không đánh giá các đối số được áp dụng
if
trừ khi chúng sẽ được trả về
Đây là môn đánh gôn, vì vậy trình thông dịch có số byte thấp nhất sẽ thắng!
(+ 3 (if false 5))
như thế nào? Nói chung, những gì thực sự là "không trả lại"? Bạn đã không chỉ định bất kỳ loại đơn vị nào sẽ được trả lại
(+ bool bool...)
logic VÀ và (- bool bool...)
logic HOẶC? Ký hiệu vòng tiêu chuẩn sẽ sử dụng +
cho OR và *
cho AND. 2. "Đầu vào không hợp lệ" có ý định bao gồm các trường hợp như thế (/ 2 0)
nào là đúng về mặt cú pháp? 3. Vì =
, nếu các giá trị không giống nhau, nó có nên trả về false
không? 4. Định nghĩa not
xuất hiện là ngược. 5. Mã thông báo là gì? Bạn nói rằng trình thông dịch phải xử lý khoảng trắng thừa, nhưng bạn không nói khoảng trắng mà nó có thể dựa vào. Đối với các câu hỏi phức tạp như thế này, bạn thực sự nên sử dụng hộp cát để có thể kiểm tra thông số kỹ thuật.
((+ 2 3) 4)
bằng 9
hoặc lỗi? Đáng chú ý, đối với các hàm var-arg, không rõ ràng khi nào nên xem xét ứng dụng một phần. Nó thậm chí còn lầy hơn với những thứ như((if true (+ 2 3) (- 5)) 4)
(if (not (array 1)) 8 false) -> false
?