Thiết kế phạm vi hoàn hảo theo nghĩa đen


9

Tôi đã suy nghĩ về cách tôi sẽ thiết kế phạm vi "hoàn hảo" theo nghĩa đen nếu tôi thiết kế một ngôn ngữ. Đối với bạn mà không biết một phạm vi nghĩa đen trong một tuyên bố đại diện cho một phạm vi các giá trị, như 1-4. Chúng thường được sử dụng nhất trong các vòng lặp for / foreach

Dường như có một vài vấn đề người ta nên tính đến

  • Hỗ trợ cho các phạm vi bao gồm và độc quyền, việc xử lý +1 hoặc -1 đến các điểm cuối có vẻ hơi khó hiểu và có lỗi.

  • Hỗ trợ cho bước, vì vậy bạn có thể tạo một phạm vi số chẵn hoặc số lẻ chẳng hạn

  • Dễ đọc, nên dễ hiểu những gì phạm vi nghĩa đen mô tả

  • Không rõ ràng, nó nên hoàn toàn không tôn giáo những gì phạm vi nghĩa đen mô tả

  • Mặc định có lẽ nên từ bao gồm đến độc quyền vì đó là những gì được sử dụng trong hầu hết các trường hợp để lặp qua các mảng, v.v.

Dù sao, một ví dụ về phạm vi nghĩa đen mà tôi đã thấy là Ruby ở dạng 1..3 cho phạm vi độc quyền (ở cuối) và 1 ... 3 cho bao gồm (ở cuối). Bạn cũng có thể làm 1..10.step (5). Sau khi xem xét cẩn thận, tôi đã tìm thấy một vài điều tôi không thích về cách tiếp cận đó (từ kiến ​​thức hạn chế về ruby ​​của tôi)

  1. Bạn chỉ có thể mô tả bao gồm và độc quyền cho cuối cùng. Trong khi mô tả hầu hết các kịch bản, nó có vẻ hơi không nhất quán.

  2. Thay đổi chỉ bằng một bổ sung. có vẻ như là một công thức để làm cho nó khó khăn để xem liệu một phạm vi là bao gồm hay độc quyền. Tôi không biết về bạn nhưng dấu chấm có xu hướng trở nên mờ nhạt :)

  3. Việc thêm phương thức như ký hiệu cho các phạm vi dường như trộn lẫn khái niệm nghĩa đen với nghĩa của một lớp có vẻ hơi không nhất quán (ngay cả khi các phạm vi được biên dịch thành một lớp)

Dù sao, sau khi cân nhắc các lựa chọn khác nhau. Tôi nghĩ ra cái này

  • [5..1] 5,4,3,2,1
  • [1..5 [ 1,2,3,4
  • ] 1..5] 2,3,4,5
  • [ 0..5..20] 0,5,10,15,20

và kể từ đó trở đi. Tôi thích nó bởi vì [thông thường từ chối một bộ và loại này phù hợp với điều đó, mặc dù điều này trái ngược với một bộ sẽ được đặt hàng.

Có một điều tôi hơi khó hiểu mặc dù có làm cho các chỉ số độc quyền / bao gồm có bắt buộc hay không, tức là nếu bạn chỉ viết 1..5 thì mặc định sẽ là 1,2,3,4 vì đây là trường hợp phổ biến nhất với mảng, v.v. Nó dễ dàng và dễ đọc hơn, nhưng ít cụ thể hơn và nếu bạn phải viết [1..5 [bạn học sớm về cách chúng hoạt động.

Vì vậy, bạn nghĩ gì, tôi đã bao gồm hầu hết các căn cứ, bỏ qua một cái gì đó? bạn sẽ làm [] bắt buộc chứ? Bạn sẽ thiết kế phạm vi chữ khác nhau trong ngôn ngữ lập trình của bạn?

Thí sinh

  • kiểu khung: [0..10 [ , với bước: [0..5..20 [
  • ký hiệu khoảng: [0..10) với bước: [0..5..20)
  • cảm thán cho sự bao quát. 0 ..! 10, với bước: 0..5 ..! 20
    • với bước khác nhau. 0 ..! 20, 5
    • tuy nhiên, điều đó sẽ bao gồm mặc định * 0..10 '
  • dài dòng: [0 đến! 20 by 5]

Tôi phải nói rằng về mặt thẩm mỹ yêu thích của tôi cho đến nay là 0 ..! 100..5 ..! 20 , tôi chỉ muốn mặc định 0..10 để bao gồm độc quyền sẽ hợp lý hơn


2
1,5,10,15,20Khoảng cách 4, 5, 5, 5?!
Peter Taylor

Rất tiếc :) đã sửa
Homde

Câu trả lời:


14

Tại sao phát minh ra những gì đã tồn tại trong Toán học?

Ký hiệu khoảng

Điều đó sẽ bao gồm điểm 'Sự không rõ ràng' của bạn vì nó đã tồn tại.

Vấn đề duy nhất của bạn sẽ là xác định bước. Có lẽ một cái gì khác trong toán học có thể giúp với điều đó?


3
Xin chào, tôi thực sự về ký hiệu khoảng. Tuy nhiên, điều khiến tôi không muốn sử dụng nó là thực tế là nó không đối xứng với cả [và) và được sử dụng cũng như không có các bước (như bạn đề cập). Sử dụng phép so sánh dường như có khả năng gây nhầm lẫn khớp nối và tôi muốn lưu chúng vào biểu thức. Sử dụng] và [là một tiêu chuẩn iso và dường như sẽ tốt hơn với việc tích hợp bước, nhưng tất nhiên đó chỉ là ý kiến ​​của tôi.
Homde

7
@MKO: Ý tưởng của bạn về việc sử dụng dấu ngoặc đơn (như [1..5[) sẽ khiến các biên tập viên nhầm lẫn ít nhất là bằng ký hiệu khoảng thời gian tiêu chuẩn.
David Thornley

2
Hmm, một ý tưởng khác, những gì về việc sử dụng! cho, tức là: 1 ..! 5 hoặc 0..5 ..! 20 (có bước)
Homde

1
@MKO: Sử dụng !để loại trừ yếu tố đầu tiên hoặc cuối cùng có thể là tốt.
Thất vọngWithFormsDesigner

8

Bạn đã thấy phạm vi Haskell? Ý tưởng của họ cho các bước tương tự như của bạn (ở giữa) nhưng được biểu thị bằng một sự khác biệt cú pháp (từ câu trả lời của @ luqui's ):

[1,2..10] = [1,2,3,4,5,6,7,8,9,10]
[1,3..10] = [1,3,5,7,9]
[4,3..0]  = [4,3,2,1,0]
[0,5..]   = [0,5,10,15,20,25,30,35...  -- infinite
[1,1..]   = [1,1,1,1,1,1,1,1,1,1,1...  -- infinite

Tôi thấy ký hiệu này rất trực quan: bạn bắt đầu liệt kê và bỏ qua cơ thể để đánh dấu nơi nó sẽ kết thúc.

Nó không bao gồm trường hợp "độc quyền", nhưng thật lòng mà nói, tôi muốn nói rõ hơn về hành vi một lần (chỉ định ràng buộc nào là bao gồm và độc quyền) và hy vọng người dùng sẽ điều chỉnh trừ khi cú pháp cực kỳ rõ ràng (và không nhầm lẫn các biên tập viên bất khả tri ngôn ngữ).


5

Bạn nên đọc về danh sách hiểu trong các ngôn ngữ cung cấp chúng.

Python, ví dụ, bao gồm các trường hợp của bạn khá độc đáo với range()chức năng và khả năng hiểu danh sách cho các trường hợp quá phức tạp để diễn đạt range().


2

Tôi tin rằng ký hiệu của bạn là không rõ ràng. Theo trực giác, [0..5..20]không nhìn vào tôi như một phạm vi với chiều rộng bước = 5. Nó thậm chí còn thất bại trong một số trường hợp góc: điều gì về việc thể hiện tập hợp (0,2) - [0..2..2]hoặc tôi nên đặt gì ở giữa?

Tôi nghĩ rằng ký hiệu lát của Python là một cách tiếp cận vững chắc: [start:end:step](bước là tùy chọn).

Nếu bạn thực sự cần hỗ trợ cho các phạm vi độc quyền và toàn diện, tôi sẽ sử dụng ký hiệu phạm vi tiêu chuẩn (nghĩa là sử dụng ([) trừ khi điều này đưa ra sự mơ hồ cú pháp trong ngôn ngữ của bạn.


1
liên quan đến các ký hiệu "chuẩn", nhà trường châu Âu dạy [], [[, ]]][, không có dấu ngoặc đơn ... và chúng tôi chuẩn là tốt hơn, tất nhiên;)
Matthieu M.

@Matthieu: Thực ra, ở đây tại Hà Lan (mà ở châu Âu), chúng tôi đã cũng dạy rằng ký hiệu chuẩn.
Frits

1

Tôi nghĩ rằng khi bạn đặt giá trị gia tăng thứ ba, tốt hơn hết bạn nên thêm phần cuối này, thay vì ở giữa, vì đây là giá trị tùy chọn và có vẻ trực quan hơn đối với các lập trình viên dày dạn hơn là thêm đối số thứ 3 tùy chọn vào giữa .

vì vậy thay vì [1..5..20] bạn có thể làm một cái gì đó như [1..20] [5] hoặc [1..20,5]


Đó là một điểm hợp lệ và có lẽ là vấn đề của hương vị, đối với tôi, dường như việc nghĩ "1 bước 5 đến 20" sẽ dễ dàng hơn thay vì "từ 1 đến 2, với bước 5" bằng cách sử dụng [1..20] [5] có vẻ hơi lộn xộn nhưng có lẽ cách tiếp cận dấu phẩy sẽ khả thi. Tôi đánh giá cao phản hồi hơn về điều đó
Homde

1
  • [1..5 [1,2,3,4
  • ] 1..5] 2,3,4,5
  • ] 1..5 [2,3,4

Tại sao không chỉ sử dụng [1..4], [2..5], [2..4]? Không bao gồm Phạm vi không mang lại nhiều lợi ích. Bạn không cần phải viết MIN + 1 hoặc MAX-1, vâng, nhưng dù sao họ cũng không cấm. Quá nhiều biến thể, imho. Ngôn ngữ lựa chọn của tôi, scala, có (1 đến 3) và (1 đến 3) [= (1 đến 2)] nhưng nó chỉ làm tôi bối rối ngay từ đầu. Bây giờ tôi luôn sử dụng 'x to y' và do đó, tùy chọn mà tôi không sử dụng là loại trừ, nhưng tất nhiên tôi không được hưởng lợi từ Tùy chọn mà tôi không sử dụng.

  • [5..1] 5,4,3,2,1

tất nhiên là (1 đến MAX) (x => y = (MAX + 1) - x) nhưng đó là nhiều bản tóm tắt và không thân thiện với người dùng.

  • [0..5..20] 0,5,10,15,20

tất nhiên (0 đến 4) (x => y = x * 5) không quá nhiều bản tóm tắt. Tranh chấp.


Lợi ích chính của việc loại trừ phạm vi, afaik, là số lượng phần tử là sự khác biệt của các điểm cuối.
Justin L.

@JustinL.: 5-1 là 4 trong đại số của tôi nhưng chứa 3 yếu tố, không bao gồm các ranh giới: 2, 3, 4.
người dùng không biết

1

Điều gì về một cái gì đó như thế này:

  • [5..1] 5,4,3,2,1
  • [1..5] [i, e] 1,2,3,4
  • [5..1] [i, e] 5,4,3,2
  • [1..5] [e, i] 2,3,4,5
  • [1..5] [e, e] 2,3,4
  • [0..20] bằng 5 0,5,10,15,20

Cặp ietrong cặp ngoặc vuông thứ hai cho biết liệu bắt đầu hay kết thúc của phạm vi là bao gồm hay độc quyền (hoặc bạn có thể sử dụng inclexclnếu bạn muốn rõ ràng hơn). các by 5chỉ khoảng bước. Ví dụ đầu tiên và cuối cùng đã bao gồm giá trị đầu tiên và cuối cùng, vì vậy tôi đã bỏ qua [i,i], mà tôi nghĩ sẽ là một hành vi mặc định giả định OK.

Các giá trị mặc định có thể [i,i]dành cho bộ xác định bao gồm / độc quyền và by 1cho bộ xác định bước.

Thông thường tôi đã đề xuất ký hiệu chuẩn liên quan ([như được đề cập bởi @Dan McGrath, nhưng tôi đồng ý rằng trong mã này có thể gây nhầm lẫn.


Bất cứ ai có thể giải thích các downvote?
Thất vọngWithFormsDesigner

Tôi đã không nhìn thấy bất cứ điều gì sai trái . Tôi upvote để chống lại downvote.
Berin Loritsch

1

Và người chiến thắng là

Xin lỗi vì đã chọn giải pháp của riêng tôi, tôi thực sự đánh giá cao tất cả các ý kiến ​​và phản hồi và xin vui lòng phê bình giải pháp này nếu bạn thấy có gì sai với nó

Vì vậy, tôi quyết định đi cùng:

0..5           = 0,1,2,3,5
0..5..10       = 0,5,10
..3            = 0,1,3
!0..!5         = 1,2,3,4
3..            = 3 to infinity

segmented ranges
-
0..5,..5..20   = 0,1,2,3,4,5,10,15,20
0..3,10..5..20 = 0,1,2,3,10,15,20

Như bạn có thể thấy bao gồm là mặc định trên cả hai giác quan, đó là điều làm cho trực giác có ý nghĩa nhất đặc biệt là khi sử dụng bước. Bạn có thể dùng ! để kết thúc độc quyền.

Nhược điểm là thông thường bạn muốn sử dụng độc quyền khi làm việc với một mảng, nhưng sau đó, một lần nữa, hầu hết các lần bạn có thể nên sử dụng một cái gì đó như cho mỗi trong những trường hợp đó. Nếu bạn thực sự cần phải làm việc chống lại chỉ mục, trình phân tích cú pháp có thể nhận ra khi bạn có thể quên dấu đánh dấu loại trừ ở cuối và đưa ra cảnh báo

Tôi đã sử dụng .. trên cả hai mặt của biến bước thay vì sử dụng dấu phẩy hoặc bất cứ thứ gì khác vì đó là thứ trông sạch nhất và tôi hy vọng là dễ đọc nhất.

Tôi cũng đã sử dụng một số cú pháp bằng dấu phẩy để có thể tạo các phạm vi nơi các phần khác nhau có các bước khác nhau


Có vẻ ổn trừ khi chỉ định bước. Tôi nghĩ rằng nó sẽ sạch hơn như [0..10 by 5]. Phạm vi được phân đoạn có thể là [0..5, ..20 bằng 5], v.v. Người ta cũng có thể chỉ định [chữ số đầu tiên theo từng bước], mà (không giống như các hình thức khác) có thể cho phép kích thước bước bằng không.
supercat

0

Tôi sẽ không sử dụng mẫu '[1..5 [' cho một trong những lý do tương tự mà bạn sẽ tránh trộn parens và niềng răng - nó sẽ gây nhầm lẫn cho hầu hết các khớp nối của biên tập viên hiện có. Có lẽ sử dụng một điểm đánh dấu bên trong niềng răng, như '[1 .. | 5]'.

Điều khác cần xem xét là hành vi của các phương pháp để có được các giới hạn. Ví dụ: 'bắt đầu' / 'kết thúc' so với 'đầu tiên' / 'cuối' so với 'tối thiểu' / 'tối đa'. Họ cần phải lành mạnh cho cả giới hạn bao gồm và độc quyền, cũng như những người có kích thước bước.


0

Ruby có ký hiệu và một đối tượng Range hoạt động. Về cơ bản nó trông như thế này:

1..5  # range 1,2,3,4,5

Với Ruby, kích thước bước không phải là chức năng của phạm vi, mà là chức năng lặp qua phạm vi. Chúng tôi có thể sử dụng cùng một phạm vi ở trên và lặp lại thông qua nó khác nhau nếu chúng tôi muốn:

(1..5).step(3) { |x| puts x }
(1..5).step(2) { |x| puts x }

Vì vậy, đây là những điều bạn có thể muốn xem xét:

  • Thêm hỗ trợ ngôn ngữ cho các điểm cuối bao gồm / độc quyền có thể có vấn đề. Nếu tất cả các phạm vi được bao gồm (lựa chọn của Ruby), thì các nhà phát triển sẽ điều chỉnh các điểm cuối của phạm vi tương ứng. Làm thế nào để bạn đại diện cho các điểm cuối bao gồm hoặc độc quyền theo cách vừa rõ ràng và không mơ hồ với một ngữ pháp trình phân tích cú pháp đơn giản?
  • Bạn đang sử dụng phạm vi cho nhiều hơn là chỉ lặp đi lặp lại? Các ví dụ phổ biến bao gồm so sánh phạm vi, nối, giá trị trong so sánh phạm vi. Nếu vậy, làm thế nào để bạn đại diện cho những khả năng đó? (Xem liên kết đến lớp Phạm vi để biết ý tưởng cho từng ví dụ này.)

BTW, phạm vi khá đẹp nếu bạn cho phép chúng được bao gồm trong câu lệnh chuyển đổi giống như Ruby không:

switch(myval)
    when 0..33 then puts "Low"
    when 34..66 then puts "Medium"
    when 67..100 then puts "High"
end

Tôi không nói rằng đối tượng phạm vi của Ruby là kết thúc tất cả, nhưng đó là một triển khai hoạt động của khái niệm mà bạn đang nói đến. Chơi với nó để xem những gì bạn thích, không thích và sẽ làm khác đi.


Đọc kỹ câu hỏi, OP đã biết về các phạm vi của Ruby:Anyways, one example of range literal I've seen is Ruby which is in the form of 1..3 for an exclusive (on the end) range and 1...3 for inclusive (on the end). You can also do 1..10.step(5).
Thất vọngWithFormsDesigner

0

Một giải pháp mà tôi chắc chắn xem xét là sử dụng quá tải toán tử để cho phép, vd

1+[0..3]*5

Nó không nhất thiết phải minh bạch ngay lập tức với mọi người, nhưng một khi họ dừng lại và nghĩ rằng tôi hy vọng hầu hết các lập trình viên sẽ hiểu nó, và những người sử dụng ngôn ngữ thường xuyên sẽ chỉ học nó như một thành ngữ.

Để làm rõ, kết quả sẽ là [1, 6, 11, 16], nâng phép nhân và sau đó bổ sung trên phạm vi. Tôi đã không nhận ra rằng nó có thể mơ hồ đối với người dùng Python; Tôi nghĩ về phạm vi là tập hợp con của tổng số đơn đặt hàng hơn là danh sách. và lặp lại một bộ không có ý nghĩa.


2
Rất mơ hồ. list expression * 5cũng có thể có nghĩa là "lặp lại giá trị list expression5 lần", giống như trong Python.
nikie

Điều này trông rất kỳ quặc và tôi không chắc đây sẽ là 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,3gì ... ? 1,3,6,9,12? 5,10,15? cái gì khác, có lẽ? Dù bằng cách nào, tôi thấy ký hiệu này hoàn toàn phản trực giác. Có vẻ như đó có thể là một loại hoạt động con trỏ C kỳ lạ ...
FrustratedWithFormsDesigner
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.