完璧な範囲リテラルの設計


9

言語を設計する場合、「完全な」範囲リテラルを設計する方法を考えていました。1〜4のように、値の範囲を表すステートメント内の範囲リテラルがわからない場合。それらはfor / foreachループで最も一般的に使用されます

考慮すべきいくつかの問題があるようです

  • 包括的および排他的範囲のサポート、エンドポイントへの+1または-1の付加は、少しあいまいでエラーが発生しやすいようです。

  • ステッピングのサポート。たとえば、偶数または奇数の範囲を作成できます。

  • 読みやすさ、範囲リテラルが何を説明しているかはすぐにわかるはずです

  • あいまいさはありません。範囲リテラルが何を表すかは完全に明確でなければなりません

  • デフォルトはおそらく包括的から排他的であるべきです。それは、配列のループなどでほとんどの場合に使用されるものだからです。

とにかく、私が見た範囲リテラルの1つの例は、Rubyです。これは、排他的な(最後の)範囲の場合は1..3、包括的(最後の)の場合は1 ... 3の形式です。1..10.step(5)を実行することもできます。慎重に検討した結果、そのアプローチについて私が気に入らない点がいくつか見つかりました(ルビに関する私の限られた知識から)

  1. あなたは終わりのために包括的で排他的にのみ記述することができます。ほとんどのシナリオを説明していますが、少し矛盾しているように見えます。

  2. 追加だけで変化します。範囲が包括的であるか排他的であるかをわかりにくくするためのレシピのようです。私はあなたのことは知りませんが、ドットはぼやけたものになる傾向があります:)

  3. 範囲の表記法のようなメソッドを追加すると、リテラルの概念とクラスの概念が混ざったように見えます(クラスがクラスにコンパイルされた場合でも)

とにかく、別の選択肢を考えた後。これを思いついた

  • [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

など。私はそれが好きです。なぜなら、セットとは対照的にこれが注文されるとしても、通常はセットをデノネートし、これはちょっとそれに適合するからです。

私が少し引きずっているのは、排他的/包括的インジケーターを必須にするかどうかです。つまり、1..5とだけ書いた場合、配列の最も一般的なケースであるため、デフォルトは1,2,3,4になります。 。簡単で読みやすくなりますが、具体性は低く、[1..5 []と書かなければならない場合は、それらがどのように機能するかについて早期に学びます。

それで、あなたはどう思いますか、私はほとんどの拠点をカバーしました、何か見落としましたか?[]を必須にしますか?プログラミング言語で範囲リテラルを別の方法で設計しますか?

候補者

  • ブラケットのスタイル:[0..10 [ 、ステップと: [0..5..20 [
  • 間隔表記:[0..10) ステップを有する:[0..5..20)
  • 排他的な感嘆。0 ..!10、ステップあり:0..5 ..!20
    • 別のステップで。0 ..!20、5
    • しかし、それはデフォルト*になるだろう0..10'包括的、包括的に
  • 語句:[0から!20 by 5]

私はaestically私のお気に入りは、これまでであることを言わなければならない0 ..!1020 ..!0..5私は単にデフォルトたい、0..10包括排他的には、複数の論理だろう


2
1,5,10,15,20ギャップ4、5、5、5 ?!
Peter Taylor、

oops :)修正済み
Homde

回答:


14

なぜ数学にすでに存在するものを発明するのですか?

インターバル表記

それはすでに存在するので、それはあなたの「あいまいさ」のポイントをカバーするはずです。

あなたの唯一の問題は、足踏みを定義することです。多分数学の他の何かがそれを助けることができますか?


3
こんにちは、私は実際にはインターバル表記についてです。しかし、私が使用したくないのは、それが[と)の両方で対称的ではなく、括弧が使用されていることと、(言及されているように)ステップがないという事実でした。括弧を使用すると、中括弧の照合が混乱する可能性があるようですが、むしろ式に保存したいと思います。]と[の使用はiso標準であり、ステッピングの統合に適しているようですが、それはもちろん私の意見です。
Homde

7
@MKO:一致しない大括弧(など[1..5[)を使用するという考えは、エディターを少なくとも標準の間隔表記と同じくらい混乱させます。
David Thornley、2011

2
うーん、別のアイデア、使用についてはどうですか!例:1 ..!5または0..5 ..!20(ステッピングあり)
Homde

1
@MKO:!最初または最後の要素を除外するために使用するとよいでしょう。
FrustratedWithFormsDesigner

8

ハスケル山脈を見たことがありますか?彼らのステップの考え方はあなたの(真ん中の)に似ていますが、構文の違い(@luquiの回答とは異なります)で示されています。

[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

この表記法は非常に直感的です。列挙を開始し、本文をスキップして、終了する場所をマークします。

それは「排他的」のためのケースをカバーしていませんが、率直に言って、私はむしろ一度行動について明確になるだろう(バインド指定包括的で、排他的である)、および構文がある場合を除き、ユーザーがのadjustementsを作るために期待し、非常にクリアな(と言語にとらわれないエディターを混同しないでください)。


5

リスト内包表記については、それらを提供する言語で読む必要があります。

たとえばPythonは、range()関数でかなりうまくケースをカバーし、複雑すぎてで表現できないケースのリスト内包をカバーしますrange()


2

あなたの記法は曖昧さをなくすにはほど遠いと思います。直感的に、[0..5..20]ステップ幅= 5の範囲のようには見えません。いくつかのコーナーのケースでは失敗します。セット(0,2)を表現するのは[0..2..2]どうですか。

Pythonのスライス表記はしっかりしたアプローチだと思います[start:end:step](ステップはオプションです)。

排他的および包括的範囲のサポートが本当に必要な場合は、標準の範囲表記(つまり、(およびを使用[)を使用します。これにより、言語に構文のあいまいさが生じない限り、使用します。


1
「標準」の表記については、欧州の学校は教えていない[][[]]そして][、何の括弧を...そして私達の標準はもちろん、良いです;)
マシューM.

@Matthieu:実際には、ここ(オランダのあるヨーロッパで)、我々はまた、標準的な表記法と教えられました。
フリット

1

3番目の増分値を設定する場合、これはオプションの値であり、中間にオプションの3番目の引数を追加するよりも経験豊富なプログラマにとって直感的に思えるため、これを途中ではなく最後に追加する方がよいと思います。 。

したがって、[1..5..20]の代わりに、[1..20] [5]または[1..20,5]のようにすることができます


それは妥当なポイントであり、おそらく好みの問題です。[1..20]を使用して「1から2、ステップ5を使用する」よりも「1ステップ5から20」を考える方が簡単だと思いました。 [5]は少し雑然として見えますが、おそらくカンマアプローチが実行可能でしょう。それについてもっとフィードバックを
いただければ幸い

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

[1..4]、[2..5]、[2..4]を使用しないのはなぜですか?範囲を除外しても、大きなメリットはありません。はい、MIN + 1やMAX-1を書く必要はありませんが、とにかく禁止されていません。バリエーションが多すぎますね。私の選択言語であるscalaには(1から3)と(1から3)[=(1から2)]がありますが、最初は混乱してしまいました。私は常に「x to y」を使用しており、したがって、使用しないオプションは除外オプションであることを知っていますが、もちろん、使用しないオプションのメリットはありません。

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

もちろん(1からMAX)(x => y =(MAX + 1)-x)ですが、これは定型文であり、ユーザーフレンドリーではありません。

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

もちろん(0から4)(x => y = x * 5)は定型ではありません。異議あり。


afaik、範囲を除外する主な利点は、要素の数がエンドポイントの違いであることです。
ジャスティンL.

@JustinL .: 5-1は私の代数では4ですが、境界を除いて3つの要素が含まれています。2、3、4
ユーザー不明

1

このようなものはどうですか:

  • [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] 5 0,5,10,15,20

角括弧の第二の対に初めまたは範囲の終了を含むか含まないかどうかを示す(またはあなたが使用することができ、そして、あなたはより明確にする場合)。これは、ステップ間隔を示します。最初と最後の例には最初と最後の値が含まれているため、を省略しました。これは、デフォルトの動作として想定されるOKだと思います。ieinclexclby 5[i,i]

デフォルト値は[i,i]、包含/排他指定子とby 1ステップ指定子​​の場合があります。

通常、私は含む標準的な表記法を示唆しているだろう([@Danマクグラスで述べたように、私はコードで、これが混乱に見えることができることに同意するものとします。


誰もが反対票を説明できますか?
FrustratedWithFormsDesigner

私は明らかに間違ったことを何も見ませんでし。私は反対票を打ち消すことに賛成した。
Berin Loritsch

1

そして勝者は

私自身のソリューションを選択して申し訳ありません。すべてのコメントとフィードバックに本当に感謝しています。何か問題を見つけた場合は、このソリューションを評価してください。

だから私は一緒に行くことにしました:

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

両方の意味で包括的がデフォルトであることがわかるので、特にステッピングを使用する場合、それが直感的に最も理にかなっています。使えます!終わりを独占的にする。

欠点は、通常、配列を操作するときに排他的に使用することですが、ほとんどの場合、そのような場合はおそらくfor-eachのようなものを使用する必要があります。本当にインデックスに対して作業する必要がある場合、パーサーは最後に除外マーカーを忘れた可能性があることを認識し、警告を発行することができます

私は、コンマなどを使用する代わりに、ステップ変数の両側で..を使用していきました。

私はまた、コンマのある構文を入れて、異なる部分が異なるステップを持つ範囲を作成できるようにしました


ステップを指定する場合を除いて、問題ないようです。[0..10 by 5]のようにすればよりクリーンになると思います。セグメント化された範囲は[0..5、..20 by 5]のようになります。[他の形式とは異なり]最初のステップからのnumitemsを指定して、ゼロのステップサイズを可能にすることもできます。
スーパーキャット2014

0

括弧と中括弧の混在を避けるのと同じ理由の1つで「[1..5 [」フォームを使用しません。既存のエディターの大括弧のマッチングが混乱します。おそらく、 '[1 .. | 5]'のように中括弧の内側にマーカーを使用します。

考慮すべきもう1つのことは、制限を取得するためのメソッドの動作です。たとえば、「開始」/「終了」対「最初」/「最後」対「最小」/「最大」。それらは、包括的および排他的制限の両方、ならびにステップサイズの制限に対して正気である必要があります。


0

Rubyには表記法と機能するRangeオブジェクトがあります。基本的には次のようになります。

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

Rubyでは、ステップサイズは範囲の関数ではなく、範囲を反復する関数です。上記と同じ範囲を使用し、以下のようにしたい場合は異なる方法で反復することができます。

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

だからここにあなたが考慮したいかもしれないものがあります:

  • 包括的/排他的エンドポイントの言語サポートを追加すると、問題が発生する可能性があります。すべての範囲が包括的である場合(Rubyの選択)、開発者はそれに応じて範囲のエンドポイントを調整します。エンドポイントの包括性または排他性を、単純なパーサーの文法で視覚的に明確かつ明確な方法でどのように表現しますか?
  • 範囲を単に反復する以上のものに使用していますか?一般的な例には、範囲比較、スプライシング、範囲比較における値が含まれます。もしそうなら、それらの可能性をどのように表現しますか?(これらの各例のアイデアについては、Rangeクラスへのリンクを参照してください。)

ところで、Rubyのように範囲をswitchステートメントに含めることを許可すると、範囲はかなり良くなります。

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

Rubyのrangeオブジェクトがすべてであると言っているわけではありませんが、それはあなたが話している概念の実用的な実装です。それで遊んで、好きなこと、嫌いなこと、そして違うと思うことを見てください。


慎重に質問を読んで、OPは、すでに 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).
FrustratedWithFormsDesigner

0

私が確かに検討する1つの解決策は、演算子のオーバーロードを使用して、たとえば

1+[0..3]*5

それは必ずしもすべての人にすぐに透過的であるとは限りませんが、一旦停止して、ほとんどのプログラマーがそれを理解してくれると思います。この言語を定期的に使用する人は、慣用句として単にそれを学ぶでしょう。

明確にするために、結果はになり[1, 6, 11, 16]ます。乗算を解除してから、範囲全体で加算します。Pythonユーザーにとってあいまいになる可能性があることに気づかなかった。範囲はリストではなく、注文全体のサブセットと考えています。セットを繰り返しても意味がありません。


2
非常にあいまいです。 list expression * 5list expressionPythonの場合のように、「値を5回繰り返す」ことも意味します。
nikie、

これは非常に奇妙に見え、これがどうなるかわかりません... 1,2,3,1,2,3,1,2,3,1,2,3,1,2,3,1,2,31,3,6,9,125,10,15?他に何か、たぶん?どちらにしても、この表記は完全に直観に反するものです。それは多分ある種の奇妙なCポインタ操作のように見えます...
FrustratedWithFormsDesigner
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.