Câu trả lời:
*
cho đầu raBởi vì bạn có thể xuất ra bằng cách để lại một chuỗi trên ngăn xếp , có thể hữu ích khi tích lũy chuỗi bằng cách sử dụng *
thay vì xuất ra S
. Giả sử thử thách của bạn là "lấy một chuỗi và nối thêm một khoảng trắng", cách thực hiện với đầu ra sẽ là:
S( )S
Mặt khác, cách thực hiện với nó *
ngắn hơn một byte:
( )*
Vấn đề là nếu đầu ra của bạn có nhiều tích lũy, nó có thể tốn byte để xử lý phần tử đầu ra trên ngăn xếp.
Nếu bạn cần sử dụng một đoạn mã rất nhiều, sẽ rất hợp lý khi lưu trữ mã đó trên ngăn xếp và sao chép và lặp lại mã đó mỗi giờ. Cho đến nay, đó chỉ là lập trình Underload bình thường. Thật không may, việc giữ một giá trị xung quanh ngăn xếp trong một thời gian dài là khó khăn và có xu hướng khiến mã của bạn trở nên dài dòng và điều đó đúng ngay cả khi giá trị là một hàm chứ không phải dữ liệu. Điều này trở nên tồi tệ hơn rất nhiều nếu bạn có nhiều chức năng cần được sử dụng lại nhiều lần.
Trong loại chương trình lớn hơn có thể được hưởng lợi từ một số chức năng được sử dụng lại, một giải pháp bạn có thể sử dụng là tạo ra một chức năng lớn có thể thực hiện bất kỳ mục đích nào của chúng tùy thuộc vào cách gọi của nó (dựa trên những gì bên dưới nó trên ngăn xếp, hoặc thông qua sử dụng còn gọi chuỗi hơn là chỉ ^
; một hàm được viết cẩn thận có thể phân biệt ^^
từ ^:^
từ ^*^
từ ^~^
, cho bạn bốn biệt, chuỗi khá ngắn). Bạn cũng có thể lưu trữ những thứ hữu ích khác, chẳng hạn như chuỗi mà bạn sử dụng nhiều lần, trong "từ điển" này. Lưu ý rằng nếu bạn sử dụng từ điển nhiều, có thể có ý nghĩa để biến nó thành một loại câu đố, đẩy một bản sao của nó trở lại ngăn xếp, do đó bạn không cần phải sao chép bằng tay:
để có thể sử dụng nó mà không mất khả năng sử dụng nó trong tương lai.
^!!!!^
tra cứu kiểu ưa thích của tôi (mà tôi cũng đã sử dụng trong một số ví dụ khác trên trang, đặc biệt là trong phần thu nhỏ.) Mặc dù điều đó có thể không tìm kiếm ngắn nhất.
Một ví dụ đơn giản, cách triển khai booleans thường thấy nhất là !()
false (tức là số nguyên 0) và chuỗi null cho true (tức là số 1), nhưng nếu bạn gặp vấn đề chủ yếu dựa trên XOR logic, nó có thể tạo ra nhiều hơn ý nghĩa khi sử dụng chuỗi null cho sai và ~
đúng (định dạng dữ liệu này có thể được chuyển đổi thành bất kỳ định dạng boolean nào khác bằng cách sử dụng (false)~(true)~^!
và cho phép triển khai rất ngắn gọn *
cho XOR.
Có thể thực hiện nguyên tắc chung này hơn nữa và sử dụng các hàm mà chương trình của bạn sẽ cần sau này như một phần của các giá trị dữ liệu của bạn; tiết kiệm việc phải lưu trữ các chức năng và dữ liệu riêng biệt trên ngăn xếp. Điều này có thể làm cho dòng điều khiển trở nên khó hiểu hơn, nhưng khi chơi golf, khả năng bảo trì thường phải ngồi ở ghế sau, và dù sao thì Underload cũng không thể sử dụng được.
(!)
và (~!)
cho booleans, nhưng cách của bạn có vẻ tốt hơn.
Cách thuần túy về mặt chức năng để giảm số của Giáo hội là sử dụng hàm tiền thân tính toán lambda:
\n.n(\p.\z.z($(pT))(pT))(\z.z0[whatever you define the predecessor of 0 to be])
Trong đó 0 = \ x. \ Yy, T = \ x. \ Yx và $ là người kế thừa.
Viết lại trong Underload, đây là 28 byte:
(!())~(!())~(!:(:)~*(*)*~)~^!
Điều này không sao, nhưng chúng ta có thể khai thác một số thuộc tính hữu ích của Underload, cụ thể là :!
và ()*
không phải là không hoạt động. Điều này có nghĩa là, đối với một số n
, :ⁿ!!()()*ⁿ
(trong đó thời gian cⁿ
được c
lặp lại n
) mang lại n-1. Ví dụ, làm điều này cho số 3 của Giáo hội mang lại điều này:
:::!!()()***
Loại bỏ các cặp no-op, chúng tôi nhận được:
:*
Đó là 2.
Vì vậy, đây là hoạt động tiền nhiệm mới và ngắn hơn:
:(:)~^(!!()())*~(*)~^*
Đây là 7 byte ngắn hơn.
(()~(:))~:(^!!())*~(*)~^**
vẫn ngắn hơn 3 byte.
Underload thực sự có hai ngăn xếp Xếp chồng chuỗi và chồng lệnh tạo mã nguồn. ^
Hướng dẫn của Underload cho phép chúng ta di chuyển các chuỗi từ ngăn xếp cũ sang ngăn xếp sau. Bằng cách này, chúng ta có thể tiết kiệm rất nhiều thao tác ngăn xếp không cần thiết.
Ví dụ: giả sử chúng ta có (a)(b)(c)
trên ngăn xếp chính và chúng ta muốn ghép hai phần tử dưới cùng, bỏ qua (c)
, để có được (ab)(c)
. Cách ngây thơ để làm điều này là xoay ngăn xếp để lấy (c)(a)(b)
và sau đó nối lại và hoán đổi lại:
a~a~*~a*^*~
Điều này thật tệ. Sử dụng a~a~*~a*^
để xoay ngăn xếp như thế này là vô cùng tốn kém, và nên tránh khi có thể. (c)
Thay vào đó, bằng cách đưa vào không gian chương trình, điều này có thể rút ngắn bốn byte:
a(*)~*^
Ý tưởng là thực hiện các hướng dẫn bạn muốn thực hiện và sau đó thêm một hướng dẫn để đẩy (c)
lùi vào cuối, sau đó đánh giá kết quả. Điều này có nghĩa là chúng ta không phải lo lắng (c)
cho đến khi nó bị đẩy lùi sau khi chúng ta kết thúc.
(*)~a*^
, mà tôi nghĩ là có thể ghép lại nhiều hơn một chút. Thực chất ~a*^
là dip
mệnh lệnh từ Joy.
eval
lệnh, tôi chưa bao giờ thấy một ngôn ngữ như thế trước đây.